Merge "ASoC: wcd9xxx: Wait enough time during mbhc calibration"
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
new file mode 100644
index 0000000..6508329
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -0,0 +1,78 @@
+* ARM CPUs binding description
+
+The device tree allows to describe the layout of CPUs in a system through
+the "cpus" node, which in turn contains a number of subnodes (ie "cpu")
+defining properties for every cpu.
+
+Bindings for CPU nodes follow the ePAPR standard, available from:
+
+http://devicetree.org
+
+For the ARM architecture every CPU node must contain the following properties:
+
+- device_type: must be "cpu"
+- reg: property matching the CPU MPIDR[23:0] register bits
+ reg[31:24] bits must be set to 0
+- compatible: should be one of:
+ "arm,arm1020"
+ "arm,arm1020e"
+ "arm,arm1022"
+ "arm,arm1026"
+ "arm,arm720"
+ "arm,arm740"
+ "arm,arm7tdmi"
+ "arm,arm920"
+ "arm,arm922"
+ "arm,arm925"
+ "arm,arm926"
+ "arm,arm940"
+ "arm,arm946"
+ "arm,arm9tdmi"
+ "arm,cortex-a5"
+ "arm,cortex-a7"
+ "arm,cortex-a8"
+ "arm,cortex-a9"
+ "arm,cortex-a15"
+ "arm,arm1136"
+ "arm,arm1156"
+ "arm,arm1176"
+ "arm,arm11mpcore"
+ "faraday,fa526"
+ "intel,sa110"
+ "intel,sa1100"
+ "marvell,feroceon"
+ "marvell,mohawk"
+ "marvell,xsc3"
+ "marvell,xscale"
+ "qcom,krait"
+
+Example:
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x0>;
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x1>;
+ };
+
+ CPU2: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x100>;
+ };
+
+ CPU3: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x101>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 23498e5..6ef2b77 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -24,6 +24,8 @@
Optional properties
+- qcom,freq-control-mask: The cpu mask that will be used to determine if a
+ core can be used for freq control.
- qcom,core-limit-temp: Threshold temperature to start shutting down cores
in degC
- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
@@ -77,6 +79,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>
qcom,core-limit-temp = <90>;
qcom,core-temp-hysterisis = <10>;
qcom,core-control-mask = <7>;
diff --git a/Documentation/devicetree/bindings/arm/msm/pm_snoc_client.txt b/Documentation/devicetree/bindings/arm/msm/pm_snoc_client.txt
new file mode 100644
index 0000000..4f7111f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pm_snoc_client.txt
@@ -0,0 +1,35 @@
+* MSM PM SNOC client
+
+MSM PM SNOC client device is used to setup a bus request for 100 Mhz for the
+SNOC bus when the Apps cores are active. This bus request helps mitigate the
+exit latency from power collapse in cases where there aren't any active bus
+requests for SNOC.
+
+This device is dependent on the pm-8x60 device, which configures the low power
+mode of respective cores.
+
+The required properties of this device are:
+
+- compatible: qcom,pm-snoc-client
+- qcom,msm-bus,name: String representing the client-name
+- qcom,msm-bus,num-cases: Total number of usecases
+- qcom,msm-bus,active-only: Boolean context flag for requests in active or
+ dual (active & sleep) contex
+- qcom,msm-bus,num-paths: Total number of master-slave pairs
+- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing:
+ master-id, slave-id, arbitrated bandwidth
+ in KBps, instantaneous bandwidth in KBps
+
+
+Example:
+ qcom,pm-snoc-client {
+ compatible = "qcom,pm-snoc-client";
+ qcom,msm-bus,name = "ocimem_snoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors =
+ <22 512 0 0>,
+ <22 512 320000 3200000>;
+ };
+
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 436dfc7..052feeb 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -72,6 +72,20 @@
This is used to override faulty hardware readings.
- qcom,strtstp-sleepwake: Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
+The following properties are optional as collecting data via coresight might
+not be supported for every chipset. The documentation for coresight
+properties can be found in:
+Documentation/devicetree/bindings/coresight/coresight.txt
+
+- coresight-id Unique integer identifier for the bus.
+- coresight-name Unique descriptive name of the bus.
+- coresight-nr-inports Number of input ports on the bus.
+- coresight-outports List of output port numbers on the bus.
+- coresight-child-list List of phandles pointing to the children of this
+ component.
+- coresight-child-ports List of input port numbers of the children.
+
+
Example of A330 GPU in MSM8974:
/ {
diff --git a/Documentation/devicetree/bindings/i2c/i2c-qup.txt b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
index a7976e8..fd7b635 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-qup.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
@@ -28,10 +28,18 @@
recovery procedure.
- qcom,sda-gpio : I2C data GPIO number. Required for execution of bus
recovery procedure.
+ - qcom,active-only : Vote for core clock when the application processor goes
+ to active state and remove that vote when it goes to idle
+ state. This flag may improve service time of first i2c
+ request at the expense of power consumption. When this
+ entry is not present, voting is done by the runtime-pm
+ callbacks.
+ - qcom,master-id : Master endpoint number used for voting on clocks using
+ bus-scaling driver.
Example:
- i2c@f9966000 {
- cell-index = <0>;
+ i2c_3: i2c@f9966000 {
+ cell-index = <3>;
compatible = "qcom,i2c-qup";
reg = <0xf9966000 0x1000>;
reg-names = "qup_phys_addr";
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index 706ffe6..c7c6415 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -13,6 +13,7 @@
- qcom,iommu-pmu-event-classes: List of event classes supported.
- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
access to the IOMMU configuration registers
+- Bus scaling properties: See msm_bus.txt
- List of sub nodes, one for each of the translation context banks supported.
Required properties for each sub-node:
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index 56f4767..ed45979 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -21,6 +21,7 @@
- qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
- qcom,iommu-pmu-ncounters: Number of PMU counters per group.
- qcom,iommu-pmu-event-classes: List of event classes supported.
+- Bus scaling properties: See msm_bus.txt
- List of sub nodes, one for each of the translation context banks supported.
Each sub node has the following required properties:
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index c409ea6..ae1f648 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -50,7 +50,7 @@
RGB Led is a tri-colored led, Red, Blue & Green.
Required properties for RGB led:
-- qcom,mode: mode the led should operate in, options 0 = PWM, 1 = LPG
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
- qcom,pwm-channel: pwm channel the led will operate on
Required properties for PWM mode only:
@@ -59,6 +59,8 @@
Required properties for LPG mode only:
- qcom,duty-pcts: array of values for duty cycle to go through
- qcom,start-idx: starting point duty-pcts array
+
+Optional properties for LPG mode only:
- qcom,pause-lo: pause at low end of cycle
- qcom,pause-hi: pause at high end of cycle
- qcom,ramp-step-ms: step between each cycle (ms)
@@ -76,12 +78,28 @@
- qcom,default-state: default state of the led, should be "on" or "off"
- qcom,source-sel: select power source, default 1 (enabled)
- qcom,mode-ctrl: select operation mode, default 0x60 = Mode Sink
+- qcom,mode: mode the led should operate in, options "pwm", "lpg" and "manual"
+
+Required properties for PWM mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
+
+Required properties for LPG mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,duty-pcts: array of values for duty cycle to go through
+- qcom,start-idx: starting point duty-pcts array
+
+Optional properties for LPG mode only:
+- qcom,pause-lo: pause at low end of cycle
+- qcom,pause-hi: pause at high end of cycle
+- qcom,ramp-step-ms: step between each cycle (ms)
+- qcom,lut-flags: flags to be used in lut configuration
Keypad backlight is a backlight source for buttons. It supports four rows
and the required rows are enabled by specifying values in the properties.
Required properties for keypad backlight:
-- qcom,mode: mode the led should operate in, options 0 = PWM, 1 = LPG
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
- qcom,pwm-channel: pwm channel the led will operate on
- qcom,pwm-us: time the pwm device will modulate at (us)
- qcom,row-src-sel-val: select source for rows. One bit is used for each row.
@@ -89,6 +107,19 @@
- qcom,row-scan-val: select rows for scanning
- qcom,row-scan-en: row scan enable
+Required properties for PWM mode only:
+- qcom,pwm-us: time the pwm device will modulate at (us)
+
+Required properties for LPG mode only:
+- qcom,duty-pcts: array of values for duty cycle to go through
+- qcom,start-idx: starting point duty-pcts array
+
+Optional properties for LPG mode only:
+- qcom,pause-lo: pause at low end of cycle
+- qcom,pause-hi: pause at high end of cycle
+- qcom,ramp-step-ms: step between each cycle (ms)
+- qcom,lut-flags: flags to be used in lut configuration
+
Example:
qcom,leds@a200 {
@@ -105,12 +136,30 @@
};
};
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_pwm {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,pwm-us = <1000>;
+ };
+ };
+
qcom,leds@d000 {
status = "okay";
qcom,rgb_pwm {
label = "rgb";
linux,name = "led:rgb_red";
- qcom,mode = <0>;
+ qcom,mode = "pwm";
qcom,pwm-channel = <6>;
qcom,pwm-us = <1000>;
qcom,duty-ms = <20>;
@@ -128,7 +177,7 @@
qcom,rgb_lpg {
label = "rgb";
linux,name = "led:rgb_blue";
- qcom,mode = <1>;
+ qcom,mode = "lpg";
qcom,pwm-channel = <4>;
qcom,start-idx = <1>;
qcom,idx-len = <10>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 7616505..1836867 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -51,6 +51,9 @@
- qcom,sensor-name : should contain unique sensor name to differentiate from
other sensor
- "s5k3l1yx"
+- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
+ supplied
+- qcom,vdd-cx-name : should contain names of cx regulator
- cam_vdig-supply : should contain regulator from which digital voltage is
supplied
- cam_vana-supply : should contain regulator from which analog voltage is
@@ -191,6 +194,8 @@
qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index fced0d7..43df9cc 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -41,6 +41,8 @@
by default. This can then be overriden
writing the the module parameter
"charging_disabled".
+- qcom,duty-cycle-100p: Set this property to enable the 100% duty
+ cycle feature.
- qcom,use-default-batt-values: Set this flag to force reporting of
battery temperature of 250 decidegree
Celsius, state of charge to be 50%
@@ -56,6 +58,17 @@
- qcom,warm-bat-mv: Warm temperature battery target voltage.
- qcom,cool-bat-mv: Cool temperature battery target voltage.
- qcom,tchg-mins: Maximum total software initialized charge time.
+- qcom,bpd-detection: Select a battery presence detection scheme by
+ specifying either "bpd_thm", "bpd_id" or
+ "bpd_thm_id". "bpd_thm" selects the temperature
+ pin, "bpd_id" uses the id pin for battery presence
+ detection, "bpd_thm_id" selects both.
+ If the property is not set the hw default will
+ be used.
+- otg-parent-supply Specify a phandle to a parent supply regulator
+ for the OTG regulator.
+- boost-parent-supply Specify a phandle to a parent supply regulator
+ for the boost regulator.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
@@ -78,6 +91,7 @@
qcom,usb-chgpth:
- usbin-valid
+
qcom,chgr:
- chg-done
- chg-failed
@@ -134,6 +148,16 @@
- limit-error: Limiting error on SMBB boost.
- boost-pwr-ok: Status of boost power.
+Sub node optional properties:
+ qcom,usb-chgpth:
+ - regulator-name: A string used as a descriptive name
+ for the OTG regulator.
+ qcom,boost:
+ - regulator-min-microvolt: Minimum boost voltage setting.
+ - regulator-max-microvolt: Maximum boost voltage setting.
+ - regulator-name: A string used as a descriptive name
+ for the boost regulator.
+
Example:
pm8941-chg {
spmi-dev-container;
@@ -141,6 +165,9 @@
#address-cells = <1>;
#size-cells = <1>;
+ otg-parent-supply = <&pm8941_boost>;
+ boost-parent-supply = <&foo_parent_reg>;
+
qcom,vddmax-mv = <4200>;
qcom,vddsafe-mv = <4200>;
qcom,vinmin-mv = <4200>;
@@ -211,7 +238,7 @@
"batt-pres";
};
- qcom,usb-chgpth@1300 {
+ pm8941_chg_otg: qcom,usb-chgpth@1300 {
reg = <0x1300 0x100>;
interrupts = <0 0x13 0x0>,
<0 0x13 0x1>,
@@ -231,7 +258,7 @@
"coarse-det-dc";
};
- qcom,boost@1500 {
+ pm8941_chg_boost: qcom,boost@1500 {
reg = <0x1500 0x100>;
interrupts = <0x0 0x15 0x0>,
<0x0 0x15 0x1>;
@@ -244,3 +271,15 @@
reg = <0x1600 0x100>;
};
};
+
+In regulator specific device tree file:
+
+ &pm8941_chg_boost {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "8941_smbb_boost";
+ };
+
+ &pm8941_chg_otg {
+ regulator-name = "8941_smbb_otg";
+ };
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index f2cfe34..d58fa90 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -15,6 +15,8 @@
- qcom,retain-mems: Presence denotes a hardware requirement to leave the
forced memory retention signals in the core's clock
branch control register asserted.
+ - qcom,skip-logic-collapse: Presence denotes a requirement to leave power to
+ the core's logic enabled.
Example:
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
new file mode 100644
index 0000000..20468b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -0,0 +1,16 @@
+* Universal Flash Storage (UFS) Host Controller
+
+UFSHC nodes are defined to describe on-chip UFS host controllers.
+Each UFS controller instance should have its own node.
+
+Required properties:
+- compatible : compatible list, contains "jedec,ufs-1.1"
+- interrupts : <interrupt mapping for UFS host controller IRQ>
+- reg : <registers mapping>
+
+Example:
+ ufshc@0xfc598000 {
+ compatible = "jedec,ufs-1.1";
+ reg = <0xfc598000 0x800>;
+ interrupts = <0 28 0>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 8ce31d9..a3a9935 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -40,6 +40,15 @@
DATA GPIO PAD.
- qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
SOFs. Software workarounds are required for the same.
+- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
+ to 64 bits
+- qcom,enable_hbm: if present host bus manager is enabled.
+- qcom,disable-park-mode: if present park mode is enabled. Park mode enables executing
+ up to 3 usb packets from each QH.
+- hsic,consider-ipa-handshake: If present then hsic low power mode is
+ depend on suitable handshake with the IPA peer.
+- qcom,ahb-async-bridge-bypass: if present AHB ASYNC bridge will be bypassed such that
+ the bridge on the slave AHB is always used.
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
@@ -71,6 +80,7 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+ hsic,consider-ipa-handshake;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index de1577d..fbe2d25 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -121,11 +121,6 @@
Optional properties :
- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
-- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
- to 64 bits
-- qcom,enable_hbm: if present host bus manager is enabled.
-- qcom,disable-park-mode: if present park mode is enabled. Park mode enables executing
- up to 3 usb packets from each QH.
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index c130b26..6df1efe 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -21,6 +21,10 @@
- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+Optional properties:
+- qcom,has_autodetect_xo: boolean flag to determine whether Iris XO auto detect
+should be performed during boot up.
+
Example:
qcom,wcnss-wlan@fb000000 {
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index c56f06a..5700b8d 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -92,6 +92,7 @@
};
i2c@f9923000 {
+ status = "ok";
atmel_mxt_ts@4a {
compatible = "atmel,mxt-ts";
reg = <0x4a>;
@@ -230,8 +231,31 @@
qcom,rfr-gpio = <&msmgpio 44 0x00>;
};
+&usb_otg {
+ status = "ok";
+ qcom,hsusb-otg-otg-control = <2>;
+ qcom,hsusb-otg-mode = <3>;
+ vbus_otg-supply = <&pm8941_mvs1>;
+ qcom,usb2-enable-hsphy2;
+ qcom,dp-manual-pullup;
+
+ #address-cells = <0>;
+ interrupt-parent = <&usb_otg>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 134 0
+ 1 &intc 0 140 0
+ 2 &spmi_bus 0x0 0x0 0x9 0x0>;
+ interrupt-names = "core_irq", "async_irq", "pmic_id_irq";
+};
+
&usb3 {
qcom,charging-disabled;
+ vbus_dwc3-supply = <0>;
+ dwc3@f9200000 {
+ host-only-mode;
+ };
};
&slim_msm {
diff --git a/arch/arm/boot/dts/apq8074-v1.dtsi b/arch/arm/boot/dts/apq8074-v1.dtsi
new file mode 100644
index 0000000..c4e7b7c
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v1.dtsi
@@ -0,0 +1,48 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974-v1.dtsi"
+
+&soc {
+ qcom,qseecom@a700000 {
+ compatible = "qcom,qseecom";
+ reg = <0x0a700000 0x500000>;
+ reg-names = "secapp-region";
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,hlos-ce-hw-instance = <1>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 3936000 393600>,
+ <55 512 3936000 393600>,
+ <55 512 3936000 393600>;
+ };
+};
+
+&memory_hole {
+ qcom,memblock-remove = <0x0a700000 0x5800000>; /* Address and size of the hole */
+};
+
+&qseecom {
+ status = "disabled";
+};
+
diff --git a/arch/arm/boot/dts/apq8084-smp2p.dtsi b/arch/arm/boot/dts/apq8084-smp2p.dtsi
new file mode 100644
index 0000000..b1d21ff
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-smp2p.dtsi
@@ -0,0 +1,82 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+&soc {
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xf9011008 0x4>;
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index 7a1bbef..c74e59d 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -20,6 +20,7 @@
};
/include/ "apq8084-ion.dtsi"
+/include/ "apq8084-smp2p.dtsi"
&soc {
#address-cells = <1>;
@@ -201,6 +202,51 @@
};
};
+
+ memory_hole: qcom,msm-mem-hole {
+ compatible = "qcom,msm-mem-hole";
+ qcom,memblock-remove = <0x0dc00000 0x2000000>; /* Address and Size of Hole */
+ };
+
+ qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@fa00000 {
+ compatible = "qcom,smem";
+ reg = <0xfa00000 0x200000>,
+ <0xf9011000 0x1000>,
+ <0xfc428000 0x4000>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x100>;
+ qcom,pil-string = "adsp";
+ interrupts = <0 156 1>;
+ };
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 157 1>;
+ };
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ qcom,irq-no-suspend;
+ };
+ };
};
/include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/boot/dts/fsm9900-rumi.dts b/arch/arm/boot/dts/fsm9900-rumi.dts
new file mode 100644
index 0000000..2b380c7
--- /dev/null
+++ b/arch/arm/boot/dts/fsm9900-rumi.dts
@@ -0,0 +1,31 @@
+/* Copyright (c) 2013, 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/ "fsm9900.dtsi"
+
+/ {
+ model = "Qualcomm FSM9900 Rumi";
+ compatible = "qcom,fsm9900-rumi", "qcom,fsm9900", "qcom-sim";
+ qcom,msm-id = <188 0 0>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+};
+
+&soc {
+ uart0: serial@f9960000 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/fsm9900-sim.dts b/arch/arm/boot/dts/fsm9900-sim.dts
new file mode 100644
index 0000000..050929e
--- /dev/null
+++ b/arch/arm/boot/dts/fsm9900-sim.dts
@@ -0,0 +1,32 @@
+/* Copyright (c) 2013, 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/ "fsm9900.dtsi"
+
+/ {
+ model = "Qualcomm FSM9900 Simulator";
+ compatible = "qcom,fsm9900-sim", "qcom,fsm9900", "qcom-sim";
+ qcom,msm-id = <188 0 0>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+};
+
+&soc {
+ uart0: serial@f9960000 {
+ interrupts = <0 116 0>;
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/fsm9900.dtsi b/arch/arm/boot/dts/fsm9900.dtsi
new file mode 100644
index 0000000..766db36
--- /dev/null
+++ b/arch/arm/boot/dts/fsm9900.dtsi
@@ -0,0 +1,94 @@
+/* Copyright (c) 2013, 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/ "skeleton64.dtsi"
+
+/ {
+ model = "Qualcomm FSM9900";
+ compatible = "qcom,fsm9900";
+ interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+
+ intc: interrupt-controller@f9000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xF9000000 0x1000>,
+ <0xF9002000 0x1000>;
+ };
+
+ msmgpio: gpio@fd510000 {
+ compatible = "qcom,msm-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfd510000 0x4000>;
+ ngpio = <142>;
+ interrupts = <0 208 0>;
+ qcom,direct-connect-irqs = <5>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 2 0 1 3 0>;
+ clock-frequency = <19200000>;
+ };
+
+ serial@f9960000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf9960000 0x1000>;
+ interrupts = <0 104 0>;
+ status = "disabled";
+ };
+
+ cpu-pmu {
+ compatible = "qcom,krait-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+
+ qcom,cache_erp {
+ compatible = "qcom,cache_erp";
+ interrupts = <1 9 0>, <0 2 0>;
+ interrupt-names = "l1_irq", "l2_irq";
+ };
+
+ qcom,cache_dump {
+ compatible = "qcom,cache_dump";
+ qcom,l1-dump-size = <0x100000>;
+ qcom,l2-dump-size = <0x500000>;
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+ };
+
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mpq8092-regulator.dtsi b/arch/arm/boot/dts/mpq8092-regulator.dtsi
index e6866e5..63896e9 100644
--- a/arch/arm/boot/dts/mpq8092-regulator.dtsi
+++ b/arch/arm/boot/dts/mpq8092-regulator.dtsi
@@ -16,6 +16,14 @@
&spmi_bus {
qcom,pma8084@1 {
+ pma8084_s1: regulator@1400 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
pma8084_s3: regulator@1a00 {
regulator-min-microvolt = <1350000>;
@@ -53,19 +61,21 @@
status = "okay";
};
- pma8084_s7: regulator@2600 {
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <900000>;
+ pma8084_s8: regulator@2900 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
status = "okay";
};
- pma8084_s8: regulator@2900 {
+ pma8084_s12: regulator@3500 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
status = "okay";
};
@@ -82,8 +92,8 @@
pma8084_l2: regulator@4100 {
parent-supply = <&pma8084_s3>;
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <900000>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
@@ -100,23 +110,14 @@
pma8084_l4: regulator@4300 {
parent-supply = <&pma8084_s3>;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
};
pma8084_l6: regulator@4500 {
- parent-supply = <&pma8084_s5>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pma8084_l8: regulator@4700 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -133,24 +134,6 @@
};
pma8084_l10: regulator@4900 {
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pma8084_l11: regulator@4a00 {
- parent-supply = <&pma8084_s3>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pma8084_l12: regulator@4b00 {
- parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -158,25 +141,41 @@
status = "okay";
};
- pma8084_l13: regulator@4c00 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
+ pma8084_l11: regulator@4a00 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
};
+ pma8084_l12: regulator@4b00 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l13: regulator@4c00 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ status = "okay";
+ };
+
pma8084_l14: regulator@4d00 {
- parent-supply = <&pma8084_s5>;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <950000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
status = "okay";
};
pma8084_l15: regulator@4e00 {
- parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
@@ -185,7 +184,7 @@
};
pma8084_l16: regulator@4f00 {
- parent-supply = <&pma8084_s4>;
+ parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <750000>;
qcom,enable-time = <200>;
@@ -198,7 +197,6 @@
regulator-max-microvolt = <3150000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
- regulator-always-on;
qcom,system-load = <100000>;
status = "okay";
};
@@ -212,7 +210,7 @@
};
pma8084_l19: regulator@5200 {
- parent-supply = <&pma8084_s4>;
+ parent-supply = <&pma8084_s5>;
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
qcom,enable-time = <200>;
@@ -225,6 +223,7 @@
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -233,14 +232,16 @@
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
pma8084_l22: regulator@5500 {
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <2500000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -257,6 +258,31 @@
regulator-max-microvolt = <3075000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ status = "okay";
+ };
+
+ pma8084_l25: regulator@5800 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+ pma8084_l26: regulator@5900 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+ pma8084_l27: regulator@5A00 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
status = "okay";
};
@@ -274,6 +300,20 @@
status = "okay";
};
+ pma8084_lvs3: regulator@8200 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs4: regulator@8300 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
pma8084_mvs1: regulator@8400 {
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index d4c5061..78234e8 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -11,8 +11,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
gdsc_venus: qcom,gdsc@fd8c1024 {
compatible = "qcom,gdsc";
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 35829a7..65075e5 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -27,6 +27,13 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "lpass_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <11 512 0 0>,
+ <11 512 0 1000>;
status = "disabled";
lpass_q6_fw: qcom,iommu-ctx@fd000000 {
@@ -78,6 +85,14 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "copss_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <88 512 0 0>,
+ <88 512 0 1000>;
+
status = "disabled";
qcom,iommu-ctx@fd010000 {
@@ -161,6 +176,13 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "mdpe_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <92 512 0 0>,
+ <92 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd860000 {
@@ -196,6 +218,13 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "mdps_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>,
+ <22 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd870000 {
@@ -232,6 +261,13 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "gfx_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+ <26 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd880000 {
@@ -277,6 +313,13 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "vfe_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <29 512 0 0>,
+ <29 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd890000 {
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 0db886b..128d90c 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -205,6 +205,24 @@
};
};
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+ };
+
+ qcom,leds@a300 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa300 0x100>;
+ label = "mpp";
+ };
+
+ qcom,leds@a500 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa500 0x100>;
+ label = "mpp";
+ };
+
pm8226_gpios: gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
@@ -382,6 +400,21 @@
};
};
+ pm8226_adc_tm: vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ 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,pm8226_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 34ea33d..85a5608 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -247,7 +247,7 @@
};
- qcom,usb-chgpth@1300 {
+ pm8941_chg_otg: qcom,usb-chgpth@1300 {
status = "disabled";
reg = <0x1300 0x100>;
interrupts = <0 0x13 0x0>,
@@ -269,7 +269,7 @@
"dcin-valid";
};
- qcom,boost@1500 {
+ pm8941_chg_boost: qcom,boost@1500 {
status = "disabled";
reg = <0x1500 0x100>;
interrupts = <0x0 0x15 0x0>,
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 916345c..6bbdf9f 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -18,7 +18,10 @@
/ {
model = "Qualcomm MSM 8226 CDP";
compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
- qcom,msm-id = <145 1 0>;
+ qcom,msm-id = <145 1 0>,
+ <158 1 0>,
+ <159 1 0>,
+ <198 1 0>;
};
&soc {
@@ -240,6 +243,64 @@
};
&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "lpg";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+ };
+
qcom,pm8226@1 {
qcom,leds@d800 {
status = "okay";
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 7c19bc0..e11c963 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -34,6 +34,11 @@
coresight-id = <1>;
coresight-name = "coresight-tpiu";
coresight-nr-inports = <1>;
+
+ vdd-supply = <&pm8226_l18>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
};
replicator: replicator@fc31c000 {
diff --git a/arch/arm/boot/dts/msm8226-fluid.dts b/arch/arm/boot/dts/msm8226-fluid.dts
index 7b11200..c58b43b 100644
--- a/arch/arm/boot/dts/msm8226-fluid.dts
+++ b/arch/arm/boot/dts/msm8226-fluid.dts
@@ -16,7 +16,10 @@
/ {
model = "Qualcomm MSM 8226 FLUID";
compatible = "qcom,msm8226-fluid", "qcom,msm8226", "qcom,fluid";
- qcom,msm-id = <145 3 0>;
+ qcom,msm-id = <145 3 0>,
+ <158 3 0>,
+ <159 3 0>,
+ <198 3 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 589fe69..967eb82 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -18,7 +18,10 @@
/ {
model = "Qualcomm MSM 8226 MTP";
compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
- qcom,msm-id = <145 8 0>;
+ qcom,msm-id = <145 8 0>,
+ <158 8 0>,
+ <159 8 0>,
+ <198 8 0>;
};
&soc {
@@ -228,6 +231,64 @@
};
&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "lpg";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+ };
+
qcom,pm8226@1 {
qcom,leds@d300 {
status = "okay";
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index f917d45..f6e8f8b 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -18,7 +18,10 @@
/ {
model = "Qualcomm MSM 8226 QRD";
compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
- qcom,msm-id = <145 11 0>;
+ qcom,msm-id = <145 11 0>,
+ <158 11 0>,
+ <159 11 0>,
+ <198 11 0>;
};
&soc {
@@ -231,6 +234,64 @@
};
&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "lpg";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+ };
+
qcom,pm8226@1 {
qcom,leds@d300 {
status = "okay";
@@ -265,6 +326,18 @@
};
};
+&pm8226_bms {
+ status = "okay";
+ qcom,batt-type = <4>;
+ qcom,max-voltage-uv = <4350000>;
+};
+
+&pm8226_chg {
+ status = "okay";
+ qcom,chg-vddmax-mv = <4350>;
+ qcom,chg-vddsafe-mv = <4350>;
+};
+
&pm8226_gpios {
gpio@c000 { /* GPIO 1 */
/* XO_PMIC_CDC_MCLK enable for tapan codec */
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 3cca8b0..2405646 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -17,7 +17,10 @@
/ {
model = "Qualcomm MSM 8226 Simulator";
compatible = "qcom,msm8226-sim", "qcom,msm8226", "qcom,sim";
- qcom,msm-id = <145 16 0>;
+ qcom,msm-id = <145 16 0>,
+ <158 16 0>,
+ <159 16 0>,
+ <198 16 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b2933db..dfb9c43 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -271,6 +271,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-cdrom;
+ qcom,android-usb-swfi-latency = <1>;
};
wcd9xxx_intc: wcd9xxx-irq {
@@ -328,7 +329,7 @@
qcom,cdc-micbias-ldoh-v = <0x3>;
qcom,cdc-micbias-cfilt1-mv = <1800>;
- qcom,cdc-micbias-cfilt2-mv = <1800>;
+ qcom,cdc-micbias-cfilt2-mv = <2700>;
qcom,cdc-micbias-cfilt3-mv = <1800>;
qcom,cdc-micbias1-cfilt-sel = <0x0>;
@@ -547,6 +548,7 @@
gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
qcom,has_pronto_hw;
+ qcom,has_autodetect_xo;
};
qcom,msm-adsp-sensors {
@@ -869,6 +871,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>;
};
spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -983,8 +986,8 @@
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <56 512 0 0>,
- <56 512 3936000 393600>;
+ <55 512 0 0>,
+ <55 512 3936000 393600>;
};
qcom,qcedev@fd400000 {
@@ -1001,8 +1004,8 @@
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <56 512 0 0>,
- <56 512 3936000 393600>;
+ <55 512 0 0>,
+ <55 512 3936000 393600>;
};
};
@@ -1140,6 +1143,71 @@
};
};
+&pm8226_adc_tm {
+ /* Channel Node */
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x48>;
+ };
+
+ 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 = <3>;
+ qcom,btm-channel-number = <0x68>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ 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 = <3>;
+ qcom,btm-channel-number = <0x70>;
+ };
+
+ chan@14 {
+ label = "pa_therm0";
+ reg = <0x14>;
+ 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>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+
+ chan@17 {
+ label = "pa_therm1";
+ reg = <0x17>;
+ 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>;
+ qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+};
+
&pm8226_chg {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 2e7ba25..7ed914e 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -29,11 +29,13 @@
qcom,masterp = <2>;
qcom,tier = <2>;
qcom,hw-sel = "NoC";
- qcom,perm-mode = "Bypass";
- qcom,mode = "Bypass";
+ qcom,perm-mode = "Fixed";
+ qcom,mode = "Fixed";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <8>;
+ qcom,prio1 = <2>;
+ qcom,prio0 = <2>;
};
mas-vfe {
@@ -47,6 +49,8 @@
qcom,ws = <10000>;
qcom,qport = <2>;
qcom,mas-hw-id = <11>;
+ qcom,prio1 = <2>;
+ qcom,prio0 = <2>;
};
mas-mdpe {
@@ -55,11 +59,13 @@
qcom,masterp = <4>;
qcom,tier = <2>;
qcom,hw-sel = "NoC";
- qcom,perm-mode = "Bypass";
- qcom,mode = "Bypass";
+ qcom,perm-mode = "Fixed";
+ qcom,mode = "Fixed";
qcom,ws = <10000>;
qcom,qport = <7>;
qcom,mas-hw-id = <11>;
+ qcom,prio1 = <2>;
+ qcom,prio0 = <2>;
};
fab-bimc {
@@ -67,7 +73,7 @@
label = "fab-bimc";
qcom,gateway;
qcom,slavep = <16>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <16>;
};
@@ -77,7 +83,7 @@
label = "slv-camera-cfg";
qcom,slavep = <0>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <3>;
};
@@ -87,7 +93,7 @@
label = "slv-display-cfg";
qcom,slavep = <1>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <4>;
};
@@ -97,7 +103,7 @@
label = "slv-cpr-cfg";
qcom,slavep = <3>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <6>;
};
@@ -107,7 +113,7 @@
label = "slv-cpr-xpu-cfg";
qcom,slavep = <4>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <7>;
};
@@ -117,7 +123,7 @@
label = "slv-misc-cfg";
qcom,slavep = <6>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <8>;
};
@@ -127,7 +133,7 @@
label = "slv-misc-xpu-cfg";
qcom,slavep = <7>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <9>;
};
@@ -137,7 +143,7 @@
label = "slv-gfx3d-cfg";
qcom,slavep = <9>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <11>;
};
@@ -147,7 +153,7 @@
label = "slv-mmss-clk-cfg";
qcom,slavep = <11>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <12>;
};
@@ -157,7 +163,7 @@
label = "slv-mmss-clk-xpu-cfg";
qcom,slavep = <12>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <13>;
};
@@ -167,7 +173,7 @@
label = "slv-mnoc-mpu-cfg";
qcom,slavep = <13>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <14>;
};
@@ -177,7 +183,7 @@
label = "slv-onoc-mpu-cfg";
qcom,slavep = <14>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <15>;
};
@@ -187,7 +193,7 @@
label = "slv-service-mnoc";
qcom,slavep = <18>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <17>;
};
@@ -197,7 +203,7 @@
label = "slv-dsi-cfg";
qcom,slavep = <19>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <19>;
};
@@ -272,8 +278,8 @@
qcom,mas-hw-id = <29>;
qcom,slv-hw-id = <28>;
qcom,mode = "Fixed";
- qcom,prio-rd = <2>;
- qcom,prio-wr = <2>;
+ qcom,prio0 = <2>;
+ qcom,prio1 = <2>;
};
fab-ovnoc {
@@ -291,6 +297,9 @@
qcom,masterp = <5>;
qcom,tier = <2>;
qcom,mas-hw-id = <23>;
+ qcom,hw-sel = "NoC";
+ qcom,prio0 = <1>;
+ qcom,prio1 = <1>;
};
mas-mss {
@@ -899,6 +908,7 @@
qcom,mas-hw-id = <0>;
qcom,prio-rd = <1>;
qcom,prio-wr = <1>;
+ qcom,prio-lvl = <1>;
};
mas-mss-proc {
@@ -943,8 +953,8 @@
qcom,qport = <4>;
qcom,mas-hw-id = <25>;
qcom,mode = "Fixed";
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio0 = <1>;
+ qcom,prio1 = <1>;
};
mas-gfx3d {
@@ -952,13 +962,11 @@
label = "mas-gfx3d";
qcom,masterp = <5>;
qcom,tier = <2>;
- qcom,hw-sel = "NoC";
- qcom,perm-mode = "Bypass";
- qcom,mode = "Bypass";
+ qcom,hw-sel = "BIMC";
+ qcom,perm-mode = "Fixed";
+ qcom,mode = "Fixed";
qcom,ws = <10000>;
qcom,qport = <5>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
qcom,mas-hw-id = <6>;
};
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
new file mode 100644
index 0000000..d057260
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+&i2c {
+
+ led_flash0: qcom,led-flash@60 {
+ cell-index = <0>;
+ reg = <0x60>;
+ qcom,slave-id = <0x60 0x00 0x0011>;
+ compatible = "qcom,led-flash";
+ qcom,flash-name = "adp1600";
+ qcom,flash-type = <1>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 18 0>,
+ <&msmgpio 19 0>;
+ qcom,gpio-flash-en = <0>;
+ qcom,gpio-flash-now = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <0 0>;
+ qcom,gpio-req-tbl-label = "FLASH_EN",
+ "FLASH_NOW";
+ };
+
+ actuator0: qcom,actuator@6e {
+ cell-index = <3>;
+ reg = <0x6c>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6f {
+ compatible = "qcom,ov8825";
+ reg = <0x6f>;
+ qcom,slave-id = <0x6c 0x300a 0x8825>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "ov8825";
+ cam_vdig-supply = <&pm8110_l2>;
+ cam_vana-supply = <&pm8110_l19>;
+ cam_vio-supply = <&pm8110_l14>;
+ cam_vaf-supply = <&pm8110_l16>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 0 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 1800000 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1200000 1800000 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <200000 8000 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 13 0>,
+ <&msmgpio 21 0>,
+ <&msmgpio 20 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,csi-lane-assign = <0xe4>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6d {
+ compatible = "qcom,ov9724";
+ reg = <0x6d>;
+ qcom,slave-id = <0x20 0x0 0x9724>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "ov9724";
+ cam_vdig-supply = <&pm8110_l4>;
+ cam_vana-supply = <&pm8110_l19>;
+ cam_vio-supply = <&pm8110_l14>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 14 0>,
+ <&msmgpio 15 0>,
+ <&msmgpio 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0xe4>;
+ qcom,csi-lane-mask = <0x1>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-camera.dtsi b/arch/arm/boot/dts/msm8610-camera.dtsi
new file mode 100644
index 0000000..b1c94dd
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-camera.dtsi
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc{
+ qcom,msm-cam@fd8c0000 {
+ compatible = "qcom,msm-cam";
+ reg = <0xfd8C0000 0x10000>;
+ reg-names = "msm-cam";
+ };
+
+ qcom,csiphy@fda00c00 {
+ cell-index = <0>;
+ compatible = "qcom,csiphy";
+ reg = <0xfda00c00 0x1f4>;
+ reg-names = "csiphy";
+ interrupts = <0 78 0>;
+ interrupt-names = "csiphy";
+ };
+
+ qcom,csiphy@fda01000 {
+ cell-index = <1>;
+ compatible = "qcom,csiphy";
+ reg = <0xfda01000 0x1f4>;
+ reg-names = "csiphy";
+ interrupts = <0 79 0>;
+ interrupt-names = "csiphy";
+ };
+
+ qcom,csid@fda00000 {
+ cell-index = <0>;
+ compatible = "qcom,csid";
+ reg = <0xfda00000 0x100>;
+ reg-names = "csid";
+ interrupts = <0 50 0>;
+ interrupt-names = "csid";
+ qcom,csi-vdd-voltage = <1200000>;
+ qcom,mipi-csi-vdd-supply = <&pm8110_l4>;
+ };
+
+ qcom,csid@fda00400 {
+ cell-index = <1>;
+ compatible = "qcom,csid";
+ reg = <0xfda00400 0x100>;
+ reg-names = "csid";
+ interrupts = <0 51 0>;
+ interrupt-names = "csid";
+ qcom,csi-vdd-voltage = <1200000>;
+ qcom,mipi-csi-vdd-supply = <&pm8110_l4>;
+ };
+
+ qcom,ispif@fda00800 {
+ cell-index = <0>;
+ compatible = "qcom,ispif";
+ reg = <0xfda00800 0x200>;
+ reg-names = "ispif";
+ interrupts = <0 52 0>;
+ interrupt-names = "ispif";
+ };
+
+ qcom,vfe@fde00000 {
+ cell-index = <0>;
+ compatible = "qcom,vfe32";
+ reg = <0xfde00000 0x800>;
+ reg-names = "vfe", "vfe_vbif";
+ interrupts = <0 49 0>;
+ interrupt-names = "vfe";
+ vdd-supply = <&gdsc_vfe>;
+ };
+
+};
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index d3fc917..257a41c 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -14,6 +14,7 @@
/include/ "msm8610.dtsi"
/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
/ {
model = "Qualcomm MSM 8610 CDP";
@@ -229,6 +230,7 @@
vdd-io-supply = <&pm8110_l6>;
qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 1800000>;
qcom,vdd-io-current-level = <200 60000>;
@@ -250,8 +252,6 @@
qcom,vdd-current-level = <15000 400000>;
vdd-io-supply = <&pm8110_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <200 50000>;
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index 1766422..af0e3e4 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -21,7 +21,7 @@
cell-index = <0>;
compatible = "qcom,mdss-fb";
qcom,memory-reservation-type = "EBI1";
- qcom,memory-reservation-size = <0x800000>;
+ qcom,memory-reservation-size = <0x300000>;
};
};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index e1fe66a..abd4228 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -14,6 +14,7 @@
/include/ "msm8610.dtsi"
/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
/ {
model = "Qualcomm MSM 8610 MTP";
@@ -229,6 +230,7 @@
vdd-io-supply = <&pm8110_l6>;
qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 1800000>;
qcom,vdd-io-current-level = <200 60000>;
@@ -250,8 +252,6 @@
qcom,vdd-current-level = <15000 400000>;
vdd-io-supply = <&pm8110_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <200 50000>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9dbd71d..689392c 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -33,6 +33,7 @@
soc: soc { };
};
+/include/ "msm8610-camera.dtsi"
/include/ "msm-iommu-v0.dtsi"
/include/ "msm8610-ion.dtsi"
/include/ "msm8610-gpu.dtsi"
@@ -472,7 +473,7 @@
qcom,i2c-bus-freq = <100000>;
};
- i2c@f9928000 { /* BLSP1 QUP6 */
+ i2c: i2c@f9928000 { /* BLSP1 QUP6 */
cell-index = <6>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
@@ -736,6 +737,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>;
};
qcom,ipc-spinlock@fd484000 {
@@ -812,6 +814,43 @@
compatible = "qcom,tz-log";
reg = <0x0fe805720 0x1000>;
};
+
+ qcom,qcrypto@fd404000 {
+ compatible = "qcom,qcrypto";
+ reg = <0xfd400000 0x20000>,
+ <0xfd404000 0x8000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <1>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 3936000>;
+ };
+
+ qcom,qcedev@fd400000 {
+ compatible = "qcom,qcedev";
+ reg = <0xfd400000 0x20000>,
+ <0xfd404000 0x8000>;
+ reg-names = "crypto-base","crypto-bam-base";
+ interrupts = <0 207 0>;
+ qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <1>;
+ qcom,ce-hw-shared;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 393600 3936000>;
+ };
+
};
&gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index efd9c32..4a9820d 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -36,6 +36,8 @@
qcom,actuator-src = <&actuator0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -77,6 +79,8 @@
qcom,mount-angle = <90>;
qcom,sensor-name = "imx135";
qcom,actuator-src = <&actuator1>;
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -118,6 +122,8 @@
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -153,6 +159,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 9cbd45c..f61b83a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -37,6 +37,8 @@
qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <270>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -78,6 +80,8 @@
qcom,mount-angle = <270>;
qcom,sensor-name = "imx135";
qcom,actuator-src = <&actuator1>;
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -119,6 +123,8 @@
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -154,6 +160,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index e9d3d75..e0b572e 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -36,6 +36,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs2>;
@@ -73,6 +75,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "imx135";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,actuator-src = <&actuator1>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -115,6 +119,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs2>;
@@ -149,6 +155,8 @@
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,sensor-name = "mt9m114";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 68af4a6..6ad6213 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,6 +37,8 @@
qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -77,6 +79,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "imx135";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,actuator-src = <&actuator1>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -120,6 +124,8 @@
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -155,6 +161,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index ad5f175..a822af5 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -608,12 +608,6 @@
};
mpp@a400 { /* MPP 5 */
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-sel = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
};
mpp@a500 { /* MPP 6 */
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 669097e..5172a5a 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -51,6 +51,14 @@
/* IOMMU Data */
iommu = <&kgsl_iommu>;
+ /* Trace bus */
+ coresight-id = <67>;
+ coresight-name = "coresight-gfx";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_mmss>;
+ coresight-child-ports = <7>;
+
qcom,gpu-pwrlevels {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index ee8152d..63f6d59 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -53,7 +53,7 @@
reg = <28>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x314000>;
+ qcom,memory-reservation-size = <0x614000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index b39cc21..5e91f45 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -18,7 +18,7 @@
qcom,rgb_0 {
label = "rgb";
linux,name = "led:rgb_red";
- qcom,mode = <0>;
+ qcom,mode = "pwm";
qcom,pwm-channel = <6>;
qcom,pwm-us = <1000>;
qcom,max-current = <12>;
@@ -31,7 +31,7 @@
qcom,rgb_1 {
label = "rgb";
linux,name = "led:rgb_green";
- qcom,mode = <0>;
+ qcom,mode = "pwm";
qcom,pwm-channel = <5>;
qcom,pwm-us = <1000>;
qcom,max-current = <12>;
@@ -43,7 +43,7 @@
qcom,rgb_2 {
label = "rgb";
linux,name = "led:rgb_blue";
- qcom,mode = <0>;
+ qcom,mode = "pwm";
qcom,pwm-channel = <4>;
qcom,pwm-us = <1000>;
qcom,max-current = <12>;
@@ -65,10 +65,10 @@
pm8941_flash0: qcom,flash_0 {
qcom,max-current = <1000>;
qcom,default-state = "off";
- qcom,headroom = <0>;
+ qcom,headroom = <3>;
qcom,duration = <1280>;
qcom,clamp-curr = <200>;
- qcom,startup-dly = <1>;
+ qcom,startup-dly = <3>;
qcom,safety-timer;
label = "flash";
linux,default-trigger =
@@ -81,10 +81,10 @@
pm8941_flash1: qcom,flash_1 {
qcom,max-current = <1000>;
qcom,default-state = "off";
- qcom,headroom = <0>;
+ qcom,headroom = <3>;
qcom,duration = <1280>;
qcom,clamp-curr = <200>;
- qcom,startup-dly = <1>;
+ qcom,startup-dly = <3>;
qcom,safety-timer;
linux,default-trigger =
"flash1_trigger";
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index e63b53b..b30d65c 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -294,9 +294,19 @@
enable-active-high;
};
+ ath_chip_pwd_l: ath_chip_reset {
+ compatible = "regulator-fixed";
+ regulator-name = "ath_chip_pwd_l";
+ gpio = <&pm8941_gpios 33 0>;
+ enable-active-high;
+ };
+
bt_ar3002 {
compatible = "qca,ar3002";
qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ qca,bt-chip-pwd-supply = <&ath_chip_pwd_l>;
+ qca,bt-vdd-io-supply = <&pm8941_s3>;
+ qca,bt-vdd-pa-supply = <&pm8941_l19>;
};
bt_ar3002_sleep {
@@ -414,10 +424,6 @@
qcom,otg-capability;
};
-&pm8941_mvs1 {
- parent-supply = <&ext_5v>;
-};
-
&pm8941_mvs2 {
parent-supply = <&ext_5v>;
};
@@ -717,8 +723,10 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
/*
* Liquid has external spkrdrv supply. Give a dummy supply to
@@ -765,6 +773,7 @@
&pm8941_chg {
status = "ok";
+ otg-parent-supply = <&ext_5v>;
qcom,charging-disabled;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 4d28a1d..e798fc0 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -637,13 +637,6 @@
};
mpp@a400 { /* MPP 5 */
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-sel = <0>; /* CONSTANT */
- qcom,out-strength = <1>; /* QPNP_PIN_OUT_STRENGTH_LOW */
- qcom,master-en = <1>; /* ENABLE MPP */
};
mpp@a500 { /* MPP 6 */
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 35f3993..2114686 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -25,7 +25,7 @@
};
pm8941_mvs1: regulator@8300 {
- parent-supply = <&pm8941_boost>;
+ parent-supply = <&pm8941_chg_otg>;
qcom,enable-time = <1000>;
qcom,pull-down-enable = <1>;
interrupts = <0x1 0x83 0x2>;
@@ -552,3 +552,17 @@
regulator-always-on;
};
};
+
+&pm8941_chg {
+ otg-parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg_boost {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "8941_smbb_boost";
+};
+
+&pm8941_chg_otg {
+ regulator-name = "8941_smbb_otg";
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
index c25c385..792a78c 100644
--- a/arch/arm/boot/dts/msm8974-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -34,3 +34,7 @@
qcom,misc-ref = <&pm8941_misc>;
};
+
+&pm8941_chg {
+ qcom,bpd-detection = "bpd_thm";
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 29dce2a..d3a0bc8 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -190,9 +190,9 @@
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <1>;
- qcom,ss-power = <784>;
- qcom,energy-overhead = <190000>;
- qcom,time-overhead = <100>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
};
qcom,lpm-level@1 {
@@ -206,10 +206,10 @@
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <75>;
- qcom,ss-power = <735>;
- qcom,energy-overhead = <77341>;
- qcom,time-overhead = <105>;
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
};
@@ -224,10 +224,10 @@
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <95>;
- qcom,ss-power = <725>;
- qcom,energy-overhead = <99500>;
- qcom,time-overhead = <130>;
+ qcom,latency-us = <300>;
+ qcom,ss-power = <476>;
+ qcom,energy-overhead = <225300>;
+ qcom,time-overhead = <350>;
};
qcom,lpm-level@3 {
@@ -241,10 +241,10 @@
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <2000>;
- qcom,ss-power = <138>;
- qcom,energy-overhead = <1208400>;
- qcom,time-overhead = <3200>;
+ qcom,latency-us = <2817>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
};
qcom,lpm-level@4 {
@@ -258,44 +258,29 @@
qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <3000>;
- qcom,ss-power = <110>;
- qcom,energy-overhead = <1250300>;
- qcom,time-overhead = <3500>;
+ qcom,latency-us = <3922>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
};
qcom,lpm-level@5 {
reg = <0x5>;
qcom,mode = "pc";
qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <3000>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <1350200>;
- qcom,time-overhead = <4000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <10300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <18200>;
+ qcom,latency-us = <4922>;
+ qcom,ss-power = <68>;
+ qcom,energy-overhead = <2568180>;
+ qcom,time-overhead = <8812>;
};
- qcom,lpm-level@7 {
- reg = <0x7>;
+ qcom,lpm-level@6 {
+ reg = <0x6>;
qcom,mode= "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
@@ -303,14 +288,14 @@
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <18000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <27000>;
+ qcom,latency-us = <5890>;
+ qcom,ss-power = <60>;
+ qcom,energy-overhead = <2675900>;
+ qcom,time-overhead = <10140>;
};
- qcom,lpm-level@8 {
- reg = <0x8>;
+ qcom,lpm-level@7 {
+ reg = <0x7>;
qcom,mode= "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
@@ -318,10 +303,10 @@
qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <20000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <32000>;
+ qcom,latency-us = <8500>;
+ qcom,ss-power = <18>;
+ qcom,energy-overhead = <3286600>;
+ qcom,time-overhead = <15760>;
};
};
@@ -428,6 +413,17 @@
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ qcom,pm-snoc-client {
+ compatible = "qcom,pm-snoc-client";
+ qcom,msm-bus,name = "ocimem_snoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <54 585 0 0>,
+ <54 585 0 800000>;
+ };
+
qcom,cpu-sleep-status@f9088008{
compatible = "qcom,cpu-sleep-status";
reg = <0xf9088008 0x100>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index b37a509..63a31dc 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -81,7 +81,8 @@
<783360 465000000>,
<489600 266670000>,
<244800 133330000>;
- qcom,reg-presets = <0x80070 0x11FFF>,
+ qcom,reg-presets = <0x80004 0x1>,
+ <0x80070 0x11FFF>,
<0x80074 0xA4>,
<0x800A8 0x1FFF>,
<0x80124 0x3>,
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index a4a3efe..4367807 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -26,6 +26,35 @@
sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
};
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "qcom,krait";
+ reg = <0x0>;
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "qcom,krait";
+ reg = <0x1>;
+ };
+
+ CPU2: cpu@2 {
+ device_type = "cpu";
+ compatible = "qcom,krait";
+ reg = <0x2>;
+ };
+
+ CPU3: cpu@3 {
+ device_type = "cpu";
+ compatible = "qcom,krait";
+ reg = <0x3>;
+ };
+ };
+
memory {
secure_mem: secure_region {
linux,contiguous-region;
@@ -738,6 +767,7 @@
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <50000000>;
+ qcom,master-id = <84>;
};
i2c_1: i2c@f9923000 {
@@ -753,6 +783,7 @@
qcom,i2c-src-freq = <19200000>;
qcom,scl-gpio = <&msmgpio 3 0>;
qcom,sda-gpio = <&msmgpio 2 0>;
+ qcom,master-id = <86>;
status = "disabled";
};
@@ -767,6 +798,7 @@
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <50000000>;
+ qcom,master-id = <86>;
};
spi_0: spi@f9923000 {
@@ -1419,6 +1451,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>;
qcom,core-limit-temp = <80>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <0xe>;
@@ -1583,6 +1616,7 @@
&gdsc_venus {
qcom,clock-names = "core_clk";
+ qcom,skip-logic-collapse;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 9b18b72..bde734e 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -34,6 +34,8 @@
coresight-id = <1>;
coresight-name = "coresight-tpiu";
coresight-nr-inports = <1>;
+
+ vdd-supply = <&ext_2p95v>;
};
replicator: replicator@fc31c000 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 6e258b5..c865c58 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -190,6 +190,8 @@
<85 512 40000 640000>;
qcom,pool-64-bit-align;
qcom,enable-hbm;
+ hsic,consider-ipa-handshake;
+ qcom,ahb-async-bridge-bypass;
};
qcom,usbbam@f9a44000 {
@@ -255,7 +257,7 @@
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <3>;
qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,descriptor-fifo-size = <0x3200>;
qcom,reset-bam-on-connect;
};
qcom,pipe4 {
@@ -268,7 +270,7 @@
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <4>;
qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,descriptor-fifo-size = <0x3200>;
qcom,reset-bam-on-connect;
};
qcom,pipe5 {
@@ -281,7 +283,7 @@
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <5>;
qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,descriptor-fifo-size = <0x3200>;
qcom,reset-bam-on-connect;
};
qcom,pipe6 {
@@ -294,7 +296,7 @@
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <6>;
qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,descriptor-fifo-size = <0x3200>;
qcom,reset-bam-on-connect;
};
qcom,pipe7 {
@@ -306,8 +308,8 @@
qcom,peer-bam = <2>;
qcom,src-bam-physical-address = <0xf9a04000>;
qcom,src-bam-pipe-index = <7>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x1A80>;
+ qcom,data-fifo-size = <0xDFE>;
+ qcom,descriptor-fifo-size = <0xB30>;
qcom,reset-bam-on-connect;
};
};
diff --git a/arch/arm/boot/dts/msmsamarium-ion.dtsi b/arch/arm/boot/dts/msmsamarium-ion.dtsi
new file mode 100644
index 0000000..ea954b8
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-ion.dtsi
@@ -0,0 +1,31 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+
+ qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+ reg = <21>;
+ };
+
+ qcom,ion-heap@25 { /* IOMMU HEAP */
+ reg = <25>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msmsamarium-sim.dts b/arch/arm/boot/dts/msmsamarium-sim.dts
new file mode 100644
index 0000000..4acffae
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-sim.dts
@@ -0,0 +1,55 @@
+/* Copyright (c) 2013, 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/ "msmsamarium.dtsi"
+
+/ {
+ model = "Qualcomm MSM SAMARIUM SIM";
+ compatible = "qcom,msmsamarium-sim", "qcom,msmsamarium", "qcom,sim";
+ qcom,msm-id = <195 0 0>;
+};
+
+&uartblsp0dm2{
+ status = "ok";
+};
+
+&sdcc1 {
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+ status = "ok";
+};
+
+&sdcc2 {
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <800>;
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
new file mode 100644
index 0000000..81699b6
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -0,0 +1,90 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM SAMARIUM";
+ compatible = "qcom,msmsamarium";
+ interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+/include/ "msmsamarium-ion.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ intc: interrupt-controller@f9000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xf9000000 0x1000>,
+ <0xf9002000 0x1000>;
+ };
+
+ msmgpio: gpio@fd510000 {
+ compatible = "qcom,msm-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfd510000 0x4000>;
+ ngpio = <145>;
+ interrupts = <0 208 0>;
+ qcom,direct-connect-irqs = <8>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 2 0 1 3 0>;
+ clock-frequency = <19200000>;
+ };
+
+ uartblsp0dm2: serial@f991f000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf991f000 0x1000>;
+ interrupts = <0 109 0>;
+ status = "disabled";
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+
+ sdcc1: qcom,sdcc@f9824000 {
+ cell-index = <1>; /* SDC1 eMMC slot */
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf9824000 0x800>;
+ reg-names = "core_mem";
+ interrupts = <0 123 0>;
+ interrupt-names = "core_irq";
+
+ qcom,bus-width = <8>;
+ status = "disabled";
+ };
+
+ sdcc2: qcom,sdcc@f98a4000 {
+ cell-index = <2>; /* SDC2 SD card slot */
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf98a4000 0x800>;
+ reg-names = "core_mem";
+ interrupts = <0 125 0>;
+ interrupt-names = "core_irq";
+
+ qcom,bus-width = <4>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index a1fa53c..549bc73 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -43,10 +43,13 @@
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
CONFIG_MSM_IPC_LOGGING=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_IPC_ROUTER_SECURITY=y
+CONFIG_MSM_QMI_INTERFACE=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_RPM_REGULATOR_SMD=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
diff --git a/arch/arm/configs/fsm9900_defconfig b/arch/arm/configs/fsm9900_defconfig
new file mode 100644
index 0000000..94e18ae
--- /dev/null
+++ b/arch/arm/configs/fsm9900_defconfig
@@ -0,0 +1,261 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_XZ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_FSM9900=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MSM_MPM_OF=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_PORT_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_NET_IPIP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_NET_ACTIVITY_STATS is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MII=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_USB=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_PSTORE=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index aea092e..ba36df1 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -370,6 +370,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_SHIRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 07a15d9..7bf54ce 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -291,6 +291,10 @@
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8226=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index b385669..368078e 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -217,6 +217,8 @@
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -295,6 +297,10 @@
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8226=y
CONFIG_SND_SOC_MSM8X10=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
@@ -308,6 +314,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
@@ -359,4 +366,5 @@
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_QPNP_VIBRATOR=y
-CONFIG_QSEECOM=y
\ No newline at end of file
+CONFIG_QSEECOM=y
+CONFIG_IOSCHED_TEST=y
\ No newline at end of file
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 5e38ef1..7bb3629 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -216,6 +216,7 @@
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -293,6 +294,10 @@
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8226=y
CONFIG_SND_SOC_MSM8X10=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
@@ -306,6 +311,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
@@ -383,3 +389,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_IOSCHED_TEST=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index dda9bd3..5885c6e 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -428,6 +428,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f90e5f3..6c18a97 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -510,6 +510,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index bae4ee9..72032dc 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -459,6 +459,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_TIMER_STATS=y
+CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8036a44..091cdd9 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -37,6 +37,7 @@
CONFIG_DEFAULT_ROW=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSMSAMARIUM=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_CPU_HAS_L2_PMU=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index f434199..c48eb79 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -161,6 +161,7 @@
CONFIG_CFG80211=m
CONFIG_NL80211_TESTMODE=y
CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 2a1215d..4f2a637 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -108,12 +108,15 @@
CONFIG_NF_CT_NETLINK=y
CONFIG_NETFILTER_XT_MARK=y
CONFIG_NETFILTER_XT_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_DSCP=y
CONFIG_NETFILTER_XT_MATCH_ESP=y
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_IP_SET=y
@@ -160,6 +163,7 @@
CONFIG_CFG80211=m
CONFIG_NL80211_TESTMODE=y
CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0eecffd..6b62269 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -145,7 +145,7 @@
select CPU_V7
select GPIO_MSM_V2
select MSM_GPIOMUX
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
select MSM_RPM_REGULATOR
@@ -187,7 +187,7 @@
select CPU_V7
select GPIO_MSM_V2
select MSM_GPIOMUX
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
select MSM_RPM_REGULATOR
@@ -223,7 +223,7 @@
select GPIO_MSM_V2
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MSM_REMOTE_SPINLOCK_SFPB
select MSM_PIL
@@ -257,7 +257,7 @@
select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_MULTIMEDIA_USE_ION
@@ -292,7 +292,7 @@
select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_NATIVE_RESTART
@@ -304,6 +304,9 @@
select ARM_HAS_SG_CHAIN
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+ select MEMORY_HOLE_CARVEOUT
+ select DONT_MAP_HOLE_AFTER_MEMBANK0
+ select QMI_ENCDEC
config ARCH_MPQ8092
bool "MPQ8092"
@@ -317,6 +320,25 @@
select SPARSE_IRQ
select MSM_NOPM
+config ARCH_FSM9900
+ bool "FSM9900"
+ select ARCH_MSM_KRAITMP
+ select GPIO_MSM_V3
+ select ARM_GIC
+ select CPU_V7
+ select MSM_SCM
+ select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
+ select MSM_PIL
+ select MSM_NATIVE_RESTART
+ select MSM_RESTART_V2
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select REGULATOR
+ select ARM_HAS_SG_CHAIN
+ select MSM_RUN_QUEUE_STATS
+ select MSM_NOPM
+
config ARCH_FSM9XXX
bool "FSM9XXX"
select ARCH_MSM_SCORPION
@@ -378,7 +400,6 @@
select MSM_RESTART_V2
select MSM_SPM_V2
select MSM_PM8X60 if PM
- select MSM_SCM if SMP
select MULTI_IRQ_HANDLER
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
@@ -414,7 +435,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEXMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -456,7 +477,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEXMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -491,6 +512,26 @@
select MSM_RPM_LOG
select MSM_RPM_STATS_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+
+config ARCH_MSMSAMARIUM
+ bool "MSMSAMARIUM"
+ select ARCH_MSM_KRAITMP
+ select GPIO_MSM_V3
+ select ARM_GIC
+ select CPU_V7
+ select MSM_SCM
+ select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
+ select MSM_SPM_V2
+ select MSM_L2_SPM
+ select MSM_NATIVE_RESTART
+ select MSM_RESTART_V2
+ select MSM_PM8X60 if PM
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select ARM_HAS_SG_CHAIN
+ select MSM_RUN_QUEUE_STATS
+ select ARCH_WANT_KMAP_ATOMIC_FLUSH
endmenu
choice
@@ -1093,7 +1134,9 @@
default "0x00000000" if ARCH_MPQ8092
default "0x00000000" if ARCH_MSM8226
default "0x00000000" if ARCH_MSM8610
+ default "0x00000000" if ARCH_MSMSAMARIUM
default "0x10000000" if ARCH_FSM9XXX
+ default "0x00000000" if ARCH_FSM9900
default "0x00200000" if ARCH_MSM9625
default "0x00000000" if ARCH_MSMKRYPTON
default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1257,6 +1300,22 @@
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MSM9625 devices.
+
+ config DEBUG_FSM9900_UART
+ bool "Kernel low-level debugging messages via FSM9900 UART"
+ depends on ARCH_FSM9900
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on FSM9900 devices.
+
+ config DEBUG_MSMSAMARIUM_UART
+ bool "Kernel low-level debugging messages via MSM SAMARIUM UART"
+ depends on ARCH_MSMSAMARIUM
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on MSM SAMARIUM devices.
endchoice
choice
@@ -2663,14 +2722,25 @@
related operations of OCMEM. Both local power management
and RPM assisted power management operations are supported.
-config MSM_OCMEM_POWER_DISABLE
- bool "OCMEM Disable Power Control"
+config MSM_OCMEM_DEBUG_ALWAYS_ON
+ bool "Keep OCMEM always turned ON"
depends on MSM_OCMEM_DEBUG
help
+ Always vote for all OCMEM clocks and keep all OCMEM
+ macros turned ON and never allow them to be turned OFF.
+ Both local power management and RPM assisted power modes
+ are supported for individual macro power control operations.
+
+config MSM_OCMEM_POWER_DISABLE
+ bool "OCMEM Disable Power Control"
+ depends on MSM_OCMEM
+ help
Disable all OCMEM power management.
- This keeps all OCMEM macros turned ON at all times thus
- never allowing them to be turned OFF. Both local power
- management and RPM assisted power modes are supported.
+ Skip all OCMEM power operations that turn ON or
+ turn OFF the macros. Both local power management and
+ RPM assisted power management operations are skipped.
+ Enable this configuration if OCMEM is being exclusively
+ used as GMEM or OCIMEM.
config SENSORS_ADSP
bool "Enable Sensors Driver Support for ADSP"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 400f859..fa3344d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -121,6 +121,8 @@
ifndef CONFIG_ARCH_MSM8610
ifndef CONFIG_ARCH_APQ8084
ifndef CONFIG_ARCH_MSMKRYPTON
+ifndef CONFIG_ARCH_FSM9900
+ifndef CONFIG_ARCH_MSMSAMARIUM
obj-y += nand_partitions.o
endif
endif
@@ -132,6 +134,8 @@
endif
endif
endif
+endif
+endif
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -230,6 +234,7 @@
obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9900) += board-fsm9900.o board-fsm9900-gpiomux.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
@@ -288,7 +293,7 @@
obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
-obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o
+obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o
obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
@@ -307,10 +312,12 @@
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
+obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
+obj-$(CONFIG_ARCH_MPQ8092) += clock-8092.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8226.o
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
@@ -373,10 +380,12 @@
obj-$(CONFIG_ARCH_MSM8974) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMSAMARIUM) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_FSM9900) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 2827e65..b40c70a 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -93,6 +93,11 @@
params_phys-$(CONFIG_ARCH_FSM9XXX) := 0x10000100
initrd_phys-$(CONFIG_ARCH_FSM9XXX) := 0x12000000
+# FSM9900
+ zreladdr-$(CONFIG_ARCH_FSM9900) := 0x00008000
+ dtb-$(CONFIG_ARCH_FSM9900) := fsm9900-rumi.dtb
+ dtb-$(CONFIG_ARCH_FSM9900) := fsm9900-sim.dtb
+
# MPQ8092
zreladdr-$(CONFIG_ARCH_MPQ8092) := 0x00008000
@@ -100,3 +105,7 @@
zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-rumi.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-sim.dtb
+
+# MSMSAMARIUM
+ zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSMSAMARIUM) += msmsamarium-sim.dtb
diff --git a/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c b/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
new file mode 100644
index 0000000..8adf8ca
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2013, 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/mfd/pm8xxx/batterydata-lib.h>
+
+static struct single_row_lut fcc_temp = {
+ .x = {-20, 0, 25, 40, 60},
+ .y = {2096, 2124, 2121, 2118, 2103},
+ .cols = 5
+};
+
+static struct single_row_lut fcc_sf = {
+ .x = {0},
+ .y = {100},
+ .cols = 1
+};
+
+static struct sf_lut rbatt_sf = {
+ .rows = 30,
+ .cols = 5,
+ .row_entries = {-20, 0, 25, 40, 60},
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60,
+ 55, 50, 45, 40, 35, 30, 25, 20, 16, 13,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
+ .sf = {
+ {2422, 324, 100, 79, 72},
+ {2417, 325, 100, 79, 71},
+ {2344, 327, 100, 80, 72},
+ {2416, 336, 102, 81, 73},
+ {2072, 354, 107, 82, 73},
+ {1961, 372, 113, 84, 75},
+ {1929, 341, 118, 87, 77},
+ {1929, 321, 130, 93, 80},
+ {2041, 306, 140, 104, 85},
+ {2202, 292, 119, 96, 83},
+ {2374, 290, 98, 80, 73},
+ {2550, 292, 98, 79, 72},
+ {2727, 294, 99, 81, 73},
+ {2904, 303, 100, 82, 75},
+ {3091, 323, 100, 81, 73},
+ {3278, 348, 100, 80, 73},
+ {3470, 376, 99, 79, 72},
+ {3627, 386, 100, 79, 72},
+ {3672, 398, 100, 80, 71},
+ {3812, 424, 100, 80, 73},
+ {3895, 443, 101, 80, 73},
+ {3985, 465, 102, 82, 75},
+ {4094, 497, 105, 83, 76},
+ {4211, 533, 109, 85, 79},
+ {4335, 579, 113, 87, 80},
+ {4505, 612, 113, 85, 76},
+ {4693, 643, 113, 86, 77},
+ {4930, 712, 120, 90, 81},
+ {5283, 835, 145, 111, 107},
+ {10293, 15765, 5566, 6904, 2547},
+ }
+};
+
+static struct pc_temp_ocv_lut pc_temp_ocv = {
+ .rows = 31,
+ .cols = 5,
+ .temp = {-20, 0, 25, 40, 60},
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60,
+ 55, 50, 45, 40, 35, 30, 25, 20, 16, 13,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+ .ocv = {
+ {4340, 4340, 4335, 4330, 4323},
+ {4217, 4260, 4265, 4263, 4258},
+ {4135, 4203, 4207, 4205, 4201},
+ {4084, 4150, 4152, 4150, 4146},
+ {3992, 4101, 4101, 4097, 4093},
+ {3934, 4049, 4051, 4046, 4044},
+ {3889, 3974, 3995, 3998, 3999},
+ {3852, 3926, 3958, 3961, 3959},
+ {3832, 3892, 3921, 3923, 3921},
+ {3819, 3859, 3874, 3877, 3877},
+ {3807, 3831, 3838, 3838, 3838},
+ {3796, 3809, 3815, 3815, 3814},
+ {3784, 3792, 3797, 3797, 3796},
+ {3770, 3780, 3783, 3782, 3781},
+ {3754, 3770, 3772, 3769, 3764},
+ {3737, 3758, 3763, 3754, 3742},
+ {3717, 3737, 3744, 3735, 3720},
+ {3700, 3713, 3718, 3710, 3696},
+ {3687, 3701, 3692, 3683, 3671},
+ {3674, 3695, 3689, 3681, 3669},
+ {3667, 3692, 3688, 3680, 3669},
+ {3659, 3690, 3687, 3680, 3668},
+ {3649, 3687, 3685, 3678, 3667},
+ {3636, 3683, 3683, 3676, 3664},
+ {3618, 3674, 3679, 3671, 3658},
+ {3596, 3652, 3663, 3652, 3632},
+ {3566, 3611, 3620, 3606, 3584},
+ {3522, 3547, 3555, 3540, 3517},
+ {3460, 3449, 3461, 3446, 3424},
+ {3356, 3282, 3312, 3299, 3273},
+ {3000, 3000, 3000, 3000, 3000}
+ }
+};
+
+
+struct bms_battery_data QRD_4v35_2000mAh_data = {
+ .fcc = 2000,
+ .fcc_temp_lut = &fcc_temp,
+ .fcc_sf_lut = &fcc_sf,
+ .pc_temp_ocv_lut = &pc_temp_ocv,
+ .rbatt_sf_lut = &rbatt_sf,
+ .default_rbatt_mohm = 172
+};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index f969e31..372f8ba 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -85,7 +85,6 @@
#include "pm.h"
#include "pm-boot.h"
#include "devices-msm8x60.h"
-#include "smd_private.h"
#include "platsmp.h"
#define MHL_GPIO_INT 30
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 500c302..67c05ba 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -31,6 +31,7 @@
#include "clock.h"
#include "devices.h"
#include "platsmp.h"
+#include "modem_notifier.h"
static struct memtype_reserve apq8084_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -82,6 +83,7 @@
*/
void __init apq8084_add_drivers(void)
{
+ msm_init_modem_notifier_list();
msm_smd_init();
msm_clock_init(&msm8084_clock_init_data);
}
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index cd95bf3..7b81c11 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -35,21 +35,6 @@
#include "clock.h"
#include "platsmp.h"
-static struct clk_lookup msm_clocks_dummy[] = {
- CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
- CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
- CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
- CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
- CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
- CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
-
-};
-
-struct clock_init_data mpq8092_clock_init_data __initdata = {
- .table = msm_clocks_dummy,
- .size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
static struct memtype_reserve mpq8092_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
},
@@ -90,8 +75,6 @@
static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
- OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
- "spmi-pmic-arb.0", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 593e2b1..8303992 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -75,7 +75,7 @@
static struct gpiomux_setting lcd_en_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
+ .pull = GPIOMUX_PULL_UP,
};
static struct gpiomux_setting gpio_keys_active = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index ccea956..e097faf 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -96,7 +96,6 @@
#include "rpm_resources.h"
#include <mach/mpm.h>
#include "clock.h"
-#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
#include "board-8930.h"
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index cb88cdc..b45e690 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -98,7 +98,6 @@
#include "rpm_resources.h"
#include <mach/mpm.h>
#include "clock.h"
-#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
#include "platsmp.h"
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 76dbaef..c8a88d7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1001,7 +1001,6 @@
},
};
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
static struct gpiomux_setting sdc3_clk_actv_cfg = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_8MA,
@@ -1082,9 +1081,6 @@
msm_gpiomux_install(msm8974_sdc3_configs,
ARRAY_SIZE(msm8974_sdc3_configs));
}
-#else
-static void msm_gpiomux_sdc3_install(void) {}
-#endif /* CONFIG_MMC_MSM_SDC3_SUPPORT */
#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
static struct gpiomux_setting sdc4_clk_actv_cfg = {
@@ -1219,7 +1215,11 @@
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
msm_gpiomux_install(&sd_card_det, 1);
- msm_gpiomux_sdc3_install();
+
+ if (machine_is_apq8074() && (of_board_is_liquid() || \
+ of_board_is_dragonboard()))
+ msm_gpiomux_sdc3_install();
+
msm_gpiomux_sdc4_install();
msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
diff --git a/arch/arm/mach-msm/board-samarium-gpiomux.c b/arch/arm/mach-msm/board-samarium-gpiomux.c
new file mode 100644
index 0000000..645cb6f
--- /dev/null
+++ b/arch/arm/mach-msm/board-samarium-gpiomux.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013, 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/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+static struct gpiomux_setting gpio_uart_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+ {
+ .gpio = 4, /* BLSP2 UART TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+ {
+ .gpio = 5, /* BLSP2 UART RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+};
+
+void __init msmsamarium_init_gpiomux(void)
+{
+ int rc;
+
+ rc = msm_gpiomux_init_dt();
+ if (rc) {
+ pr_err("%s failed %d\n", __func__, rc);
+ return;
+ }
+
+ msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
new file mode 100644
index 0000000..00d63a3
--- /dev/null
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2013, 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/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_memtypes.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_dev_auxdata msmsamarium_auxdata_lookup[] __initdata = {
+ {},
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msmsamarium_add_drivers(void)
+{
+ msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init msmsamarium_map_io(void)
+{
+ msm_map_msmsamarium_io();
+}
+
+void __init msmsamarium_init(void)
+{
+ struct of_dev_auxdata *adata = msmsamarium_auxdata_lookup;
+
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ msmsamarium_init_gpiomux();
+ board_dt_populate(adata);
+ msmsamarium_add_drivers();
+}
+
+static const char *msmsamarium_dt_match[] __initconst = {
+ "qcom,msmsamarium",
+ NULL
+};
+
+DT_MACHINE_START(MSMSAMARIUM_DT, "Qualcomm MSM Samarium(Flattened Device Tree)")
+ .map_io = msmsamarium_map_io,
+ .init_irq = msm_dt_init_irq,
+ .init_machine = msmsamarium_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_dt_timer,
+ .dt_compat = msmsamarium_dt_match,
+ .restart = msm_restart,
+ .smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index 424b694..b7f9fd7 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -325,7 +325,9 @@
CLK_DUMMY("", mmss_mmssnoc_ahb_clk.c, "", OFF),
CLK_DUMMY("", mmss_mmssnoc_axi_clk.c, "", OFF),
CLK_DUMMY("", mmss_s0_axi_clk.c, "", OFF),
- CLK_DUMMY("", ocmemcx_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem", OFF),
+ CLK_DUMMY("iface_clk", ocmemcx_ocmemnoc_clk.c,
+ "fdd00000.qcom,ocmem", OFF),
CLK_DUMMY("", oxili_ocmemgx_clk.c, "", OFF),
CLK_DUMMY("", oxili_gfx3d_clk.c, "", OFF),
CLK_DUMMY("", oxili_rbbmtimer_clk.c, "", OFF),
diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c
new file mode 100644
index 0000000..a8520e6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8092.c
@@ -0,0 +1,323 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+/*
+ * Drivers need to fill in the clock names and device names for the clocks
+ * they need to control.
+ */
+static struct clk_lookup msm_clocks_8092[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+ CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("", usb30_master_clk_src.c, "", OFF),
+ CLK_DUMMY("", tsif_ref_clk_src.c, "", OFF),
+ CLK_DUMMY("", ce1_clk_src.c, "", OFF),
+ CLK_DUMMY("", ce2_clk_src.c, "", OFF),
+ CLK_DUMMY("", ce3_clk_src.c, "", OFF),
+ CLK_DUMMY("", geni_ser_clk_src.c, "", OFF),
+ CLK_DUMMY("", gmac_125m_clk_src.c, "", OFF),
+ CLK_DUMMY("", gmac_core_clk_src.c, "", OFF),
+ CLK_DUMMY("", gmac_sys_25m_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp1_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp2_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp3_clk_src.c, "", OFF),
+ CLK_DUMMY("", pcie_aux_clk_src.c, "", OFF),
+ CLK_DUMMY("", pcie_pipe_clk_src.c, "", OFF),
+ CLK_DUMMY("", pdm2_clk_src.c, "", OFF),
+ CLK_DUMMY("", pwm_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_asic0_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_pmalive_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_rx_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_rx_oob_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc1_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc2_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hs_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hs2_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_io_cal_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", gcc_bam_dma_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bcss_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bimc_kpss_axi_mstr_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bimc_sysnoc_axi_mstr_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup1_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup1_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup2_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup2_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup3_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup4_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup4_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup5_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup5_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup6_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup6_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart5_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart6_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup1_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup1_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup2_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup2_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup3_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup4_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup4_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup5_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup5_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup6_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup6_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart5_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart6_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_boot_rom_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_xo_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_xo_div4_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_geni_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_geni_ser_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_125m_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_core_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_rx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_sys_25m_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gmac_sys_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp3_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_klm_core_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_klm_s_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_q6_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_lpass_mport_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_lpass_sway_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_mmss_a5ss_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_mmss_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pcie_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pcie_axi_mstr_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pcie_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pcie_pipe_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pcie_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_prng_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pwm_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pwm_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_asic0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_pmalive_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_rx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_rx_oob_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_spss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_usb3_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2a_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2b_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2c_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_master_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_system_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs2_system_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_io_cal_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_system_clk.c, "", OFF),
+ /* MMSS Clock Dummy */
+ CLK_DUMMY("", axi_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll0_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll1_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll2_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll3_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll6_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", vcodec0_clk_src.c, "", OFF),
+ CLK_DUMMY("", extpclk_clk_src.c, "", OFF),
+ CLK_DUMMY("", lvds_clk_src.c, "", OFF),
+ CLK_DUMMY("", mdp_clk_src.c, "", OFF),
+ CLK_DUMMY("", vbyone_clk_src.c, "", OFF),
+ CLK_DUMMY("", gfx3d_clk_src.c, "", OFF),
+ CLK_DUMMY("", vp_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg2_clk_src.c, "", OFF),
+ CLK_DUMMY("", hdmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", vbyone_symbol_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmss_spdm_axi_div_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_spdm_gfx3d_div_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_spdm_jpeg2_div_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_spdm_mdp_div_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_spdm_vcodec0_div_clk.c, "", OFF),
+ CLK_DUMMY("", afe_pixel_clk_src.c, "", OFF),
+ CLK_DUMMY("", cfg_clk_src.c, "", OFF),
+ CLK_DUMMY("", hdmi_bus_clk_src.c, "", OFF),
+ CLK_DUMMY("", hdmi_rx_clk_src.c, "", OFF),
+ CLK_DUMMY("", md_clk_src.c, "", OFF),
+ CLK_DUMMY("", ttl_clk_src.c, "", OFF),
+ CLK_DUMMY("", vafe_ext_clk_src.c, "", OFF),
+ CLK_DUMMY("", vcap_vp_clk_src.c, "", OFF),
+ CLK_DUMMY("", gproc_clk_src.c, "", OFF),
+ CLK_DUMMY("", hdmc_frcf_clk_src.c, "", OFF),
+ CLK_DUMMY("", kproc_clk_src.c, "", OFF),
+ CLK_DUMMY("", maple_clk_src.c, "", OFF),
+ CLK_DUMMY("", preproc_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdmc_frcs_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdme_frcf_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdme_vproc_clk_src.c, "", OFF),
+ CLK_DUMMY("", vdp_clk_src.c, "", OFF),
+ CLK_DUMMY("", vpu_bus_clk_src.c, "", OFF),
+ CLK_DUMMY("", vpu_frc_xin_clk_src.c, "", OFF),
+ CLK_DUMMY("", vpu_vdp_xin_clk_src.c, "", OFF),
+ CLK_DUMMY("", avsync_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_extpclk_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_lvds_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_vbyone_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_vp_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg_axi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_micro_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_top_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_extpclk_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_hdmi_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_hdmi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_lvds_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_mdp_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_mdp_lut_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_vbyone_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_vbyone_symbol_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_misc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_mmssnoc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_mmssnoc_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_s0_axi_clk.c, "", OFF),
+ CLK_DUMMY("", ocmemcx_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_ocmemgx_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_gfx3d_clk.c, "", OFF),
+ CLK_DUMMY("", oxilicx_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcss_mmss_ifdemod_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_afe_pixel_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_audio_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_axi_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_cfg_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_hdmi_bus_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_hdmi_rx_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_md_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_ttl_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_ttl_debug_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_vafe_ext_clk.c, "", OFF),
+ CLK_DUMMY("", vcap_vp_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_axi_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_core0_vcodec_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_core1_vcodec_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_vcodec0_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_axi_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_bus_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_cxo_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_frc_xin_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_gproc_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_hdmc_frcf_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_kproc_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_maple_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_preproc_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sdmc_frcs_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sdme_frcf_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sdme_frcs_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sdme_vproc_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_vdp_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_vdp_xin_clk.c, "", OFF),
+ /* BCSS broadcast */
+ CLK_DUMMY("", bcc_dem_core_b_clk_src.c, "", OFF),
+ CLK_DUMMY("", adc_01_clk_src.c, "", OFF),
+ CLK_DUMMY("", bcc_adc_0_in_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_klm_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_lnb_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_tsc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_tspp2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_vbif_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bcss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_atv_rxfe_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_atv_rxfe_resamp_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_core_clk_src.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_core_div2_clk_src.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_core_x2_b_clk_src.c, "", OFF),
+ CLK_DUMMY("", bcc_dem_core_x2_pre_cgf_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_tsc_ci_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_tsc_cicam_ts_clk_src.c, "", OFF),
+ CLK_DUMMY("", bcc_tsc_par_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_tsc_ser_clk_src.c, "", OFF),
+ CLK_DUMMY("", bcc_tspp2_clk_src.c, "", OFF),
+ CLK_DUMMY("", dig_dem_core_b_div2_clk.c, "", OFF),
+ CLK_DUMMY("", atv_x5_pre_cgc_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_albacore_cvbs_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_atv_x1_clk.c, "", OFF),
+ CLK_DUMMY("", nidaq_out_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bcss_axi_clk.c, "", OFF),
+ CLK_DUMMY("", bcc_lnb_core_clk.c, "", OFF),
+};
+
+struct clock_init_data mpq8092_clock_init_data __initdata = {
+ .table = msm_clocks_8092,
+ .size = ARRAY_SIZE(msm_clocks_8092),
+};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 7fe3f97..1f0d328 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -169,11 +169,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -2753,11 +2753,11 @@
VDD_SR2_PLL_NUM
};
-static int *vdd_sr2_levels[] = {
- [VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
- [VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
- [VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_sr2_levels[] = {
+ 0, RPM_REGULATOR_CORNER_NONE, /* VDD_SR2_PLL_OFF */
+ 1800000, RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_SR2_PLL_SVS */
+ 1800000, RPM_REGULATOR_CORNER_NORMAL, /* VDD_SR2_PLL_NOM */
+ 1800000, RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_SR2_PLL_TUR */
};
static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
@@ -3271,7 +3271,8 @@
CLK_LOOKUP("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
- CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 17468d2..5df3f3e 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -434,11 +434,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -509,7 +509,6 @@
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
-static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_MEASURE(apc0_m_clk);
static DEFINE_CLK_MEASURE(apc1_m_clk);
@@ -533,11 +532,11 @@
VDD_SR2_PLL_NUM
};
-static int *vdd_sr2_levels[] = {
- [VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
- [VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
- [VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_sr2_levels[] = {
+ 0, RPM_REGULATOR_CORNER_NONE, /* VDD_SR2_PLL_OFF */
+ 1800000, RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_SR2_PLL_SVS */
+ 1800000, RPM_REGULATOR_CORNER_NORMAL, /* VDD_SR2_PLL_NOM */
+ 1800000, RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_SR2_PLL_TUR */
};
static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
@@ -1546,6 +1545,7 @@
F_END,
};
+static struct branch_clk mmss_mmssnoc_axi_clk;
static struct rcg_clk axi_clk_src = {
.cmd_rcgr_reg = AXI_CMD_RCGR,
.set_rate = set_rate_hid,
@@ -1557,6 +1557,7 @@
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
CLK_INIT(axi_clk_src.c),
+ .depends = &mmss_mmssnoc_axi_clk.c
},
};
@@ -2320,7 +2321,6 @@
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &axi_clk_src.c,
.dbg_name = "mmss_mmssnoc_axi_clk",
.ops = &clk_ops_branch,
CLK_INIT(mmss_mmssnoc_axi_clk.c),
@@ -2336,7 +2336,6 @@
.dbg_name = "mmss_s0_axi_clk",
.ops = &clk_ops_branch,
CLK_INIT(mmss_s0_axi_clk.c),
- .depends = &mmss_mmssnoc_axi_clk.c,
},
};
@@ -2764,7 +2763,6 @@
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
- CLK_LOOKUP("bus_clk", pnoc_qseecom_clk.c, "qseecom"),
CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
@@ -3041,6 +3039,18 @@
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "scm"),
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "scm"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "scm"),
+
+ /* Add QCEDEV clocks */
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcedev"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcedev"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcedev"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcedev"),
+
+ /* Add QCRYPTO clocks */
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd404000.qcom,qcrypto"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd404000.qcom,qcrypto"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd404000.qcom,qcrypto"),
};
static struct clk_lookup msm_clocks_8610_rumi[] = {
@@ -3232,10 +3242,6 @@
/* Maintain the max nominal frequency on the MMSSNOC AHB bus. */
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
-
- /* TODO: Remove this once the bus driver is in place */
- clk_set_rate(&axi_clk_src.c, 200000000);
- clk_prepare_enable(&mmss_s0_axi_clk.c);
}
struct clock_init_data msm8610_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index ec94f00..53e35ef 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -638,11 +638,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -4212,6 +4212,7 @@
static struct branch_clk venus0_vcodec0_clk = {
.cbcr_reg = VENUS0_VCODEC0_CBCR,
+ .bcr_reg = VENUS0_BCR,
.has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -4891,6 +4892,10 @@
CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_esc1_clk.c, "fd922e00.qcom,mdss_dsi"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922e00.qcom,mdss_dsi"),
+ CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
@@ -5097,7 +5102,6 @@
CLK_LOOKUP("core_clk", camss_vfe_vfe_axi_clk.c, "fda44000.qcom,iommu"),
CLK_LOOKUP("alt_core_clk", camss_top_ahb_clk.c, "fda44000.qcom,iommu"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
- CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
@@ -5391,12 +5395,6 @@
writel_relaxed(regval | BIT(26) | BIT(25),
GCC_REG_BASE(APCS_CLOCK_BRANCH_ENA_VOTE));
}
-
- /*
- * TODO: Confirm that no clocks need to be voted on in this sleep vote
- * register.
- */
- writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
}
static void __init msm8974_clock_post_init(void)
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 5bfc4bb..3277d75 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -280,11 +280,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index e67d973..24af44e 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -175,39 +175,19 @@
cf = rcg->current_freq;
- /* Enable source clock dependency for the new freq. */
- if (c->prepare_count) {
- rc = clk_prepare(nf->src_clk);
- if (rc)
- return rc;
- }
-
- spin_lock_irqsave(&c->lock, flags);
- if (c->count) {
- rc = clk_enable(nf->src_clk);
- if (rc) {
- spin_unlock_irqrestore(&c->lock, flags);
- clk_unprepare(nf->src_clk);
- return rc;
- }
- }
+ rc = __clk_pre_reparent(c, nf->src_clk, &flags);
+ if (rc)
+ return rc;
BUG_ON(!rcg->set_rate);
/* Perform clock-specific frequency switch operations. */
rcg->set_rate(rcg, nf);
-
- /* Release source requirements of the old freq. */
- if (c->count)
- clk_disable(cf->src_clk);
- spin_unlock_irqrestore(&c->lock, flags);
-
- if (c->prepare_count)
- clk_unprepare(cf->src_clk);
-
rcg->current_freq = nf;
c->parent = nf->src_clk;
+ __clk_post_reparent(c, cf->src_clk, &flags);
+
return 0;
}
@@ -559,11 +539,8 @@
{
struct branch_clk *branch = to_branch_clk(c);
- if (!branch->bcr_reg) {
- WARN("clk_reset called on an unsupported clock (%s)\n",
- c->dbg_name);
+ if (!branch->bcr_reg)
return -EPERM;
- }
return __branch_clk_reset(BCR_REG(branch), action);
}
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 08817c0..582bccf 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -62,27 +62,31 @@
{
int level, rc = 0, i;
struct regulator **r = vdd_class->regulator;
- int **vdd_uv = vdd_class->vdd_uv;
- int **vdd_ua = vdd_class->vdd_ua;
- int max_level = vdd_class->num_levels - 1;
+ int *uv = vdd_class->vdd_uv;
+ int *ua = vdd_class->vdd_ua;
+ int n_reg = vdd_class->num_regulators;
+ int max_lvl = vdd_class->num_levels - 1;
+ int lvl_base;
- for (level = max_level; level > 0; level--)
+ for (level = max_lvl; level > 0; level--)
if (vdd_class->level_votes[level])
break;
if (level == vdd_class->cur_level)
return 0;
+ max_lvl = max_lvl * n_reg;
+ lvl_base = level * n_reg;
for (i = 0; i < vdd_class->num_regulators; i++) {
- rc = regulator_set_voltage(r[i], vdd_uv[level][i],
- vdd_uv[max_level][i]);
+ rc = regulator_set_voltage(r[i], uv[lvl_base + i],
+ uv[max_lvl + i]);
if (rc)
goto set_voltage_fail;
- if (!vdd_ua)
+ if (!ua)
continue;
- rc = regulator_set_optimum_mode(r[i], vdd_ua[level][i]);
+ rc = regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
if (rc < 0)
goto set_mode_fail;
}
@@ -95,18 +99,17 @@
return 0;
set_mode_fail:
- regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
- vdd_uv[max_level][i]);
+ regulator_set_voltage(r[i], uv[vdd_class->cur_level * n_reg + i],
+ uv[max_lvl + i]);
set_voltage_fail:
+ lvl_base = vdd_class->cur_level * n_reg;
for (i--; i >= 0; i--) {
- regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
- vdd_uv[max_level][i]);
+ regulator_set_voltage(r[i], uv[lvl_base + i], uv[max_lvl + i]);
- if (!vdd_ua)
+ if (!ua)
continue;
- regulator_set_optimum_mode(r[i],
- vdd_ua[vdd_class->cur_level][i]);
+ regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
}
return rc;
@@ -472,7 +475,7 @@
mutex_lock(&clk->prepare_lock);
/* Return early if the rate isn't going to change */
- if (clk->rate == rate)
+ if (clk->rate == rate && !(clk->flags & CLKFLAG_NO_RATE_CACHE))
goto out;
trace_clock_set_rate(name, rate, raw_smp_processor_id());
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 674ef77..2a65d2f 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -54,6 +54,7 @@
extern struct clock_init_data msm8226_clock_init_data;
extern struct clock_init_data msm8226_rumi_clock_init_data;
extern struct clock_init_data msm8084_clock_init_data;
+extern struct clock_init_data mpq8092_clock_init_data;
int msm_clock_init(struct clock_init_data *data);
int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index bf89321..483d8b3 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1270,6 +1270,7 @@
LPASS_SCSS_GP_HIGH_IRQ,
SPS_MTI_31,
A2_BAM_IRQ,
+ USB1_HS_BAM_IRQ,
};
struct msm_mpm_device_data msm9615_mpm_dev_data __initdata = {
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 30a034e..0963e27 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -48,12 +48,17 @@
struct clk **clocks;
int clock_count;
bool toggle_mems;
+ bool toggle_logic;
+ bool resets_asserted;
};
static int gdsc_is_enabled(struct regulator_dev *rdev)
{
struct gdsc *sc = rdev_get_drvdata(rdev);
+ if (!sc->toggle_logic)
+ return !sc->resets_asserted;
+
return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
}
@@ -63,15 +68,22 @@
uint32_t regval;
int i, ret;
- regval = readl_relaxed(sc->gdscr);
- regval &= ~SW_COLLAPSE_MASK;
- writel_relaxed(regval, sc->gdscr);
+ if (sc->toggle_logic) {
+ regval = readl_relaxed(sc->gdscr);
+ regval &= ~SW_COLLAPSE_MASK;
+ writel_relaxed(regval, sc->gdscr);
- ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
- TIMEOUT_US);
- if (ret) {
- dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
- return ret;
+ ret = readl_tight_poll_timeout(sc->gdscr, regval,
+ regval & PWR_ON_MASK, TIMEOUT_US);
+ if (ret) {
+ dev_err(&rdev->dev, "%s enable timed out\n",
+ sc->rdesc.name);
+ return ret;
+ }
+ } else {
+ for (i = 0; i < sc->clock_count; i++)
+ clk_reset(sc->clocks[i], CLK_RESET_DEASSERT);
+ sc->resets_asserted = false;
}
if (sc->toggle_mems) {
@@ -96,16 +108,24 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int i, ret;
+ int i, ret = 0;
- regval = readl_relaxed(sc->gdscr);
- regval |= SW_COLLAPSE_MASK;
- writel_relaxed(regval, sc->gdscr);
+ if (sc->toggle_logic) {
+ regval = readl_relaxed(sc->gdscr);
+ regval |= SW_COLLAPSE_MASK;
+ writel_relaxed(regval, sc->gdscr);
- ret = readl_tight_poll_timeout(sc->gdscr, regval,
- !(regval & PWR_ON_MASK), TIMEOUT_US);
- if (ret)
- dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+ ret = readl_tight_poll_timeout(sc->gdscr, regval,
+ !(regval & PWR_ON_MASK),
+ TIMEOUT_US);
+ if (ret)
+ dev_err(&rdev->dev, "%s disable timed out\n",
+ sc->rdesc.name);
+ } else {
+ for (i = 0; i < sc->clock_count; i++)
+ clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
+ sc->resets_asserted = true;
+ }
if (sc->toggle_mems) {
for (i = 0; i < sc->clock_count; i++) {
@@ -214,6 +234,20 @@
}
}
sc->toggle_mems = !retain_mems;
+ sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
+ "qcom,skip-logic-collapse");
+ if (!sc->toggle_logic) {
+ regval &= ~SW_COLLAPSE_MASK;
+ writel_relaxed(regval, sc->gdscr);
+
+ ret = readl_tight_poll_timeout(sc->gdscr, regval,
+ regval & PWR_ON_MASK, TIMEOUT_US);
+ if (ret) {
+ dev_err(&pdev->dev, "%s enable timed out\n",
+ sc->rdesc.name);
+ return ret;
+ }
+ }
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 690e52a..7b26bd6 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -510,6 +510,15 @@
bool mhl_enabled;
};
+/**
+ * msm_i2c_platform_data: i2c-qup driver configuration data
+ *
+ * @active_only when set, votes when system active and removes the vote when
+ * system goes idle (optimises for performance). When unset, voting using
+ * runtime pm (optimizes for power).
+ * @master_id master id number of the i2c core or its wrapper (BLSP/GSBI).
+ * When zero, clock path voting is disabled.
+ */
struct msm_i2c_platform_data {
int clk_freq;
uint32_t rmutex;
@@ -523,6 +532,8 @@
int use_gsbi_shared_mode;
int keep_ahb_clk_on;
void (*msm_i2c_config_gpio)(int iface, int config_type);
+ bool active_only;
+ uint32_t master_id;
};
struct msm_i2c_ssbi_platform_data {
@@ -604,6 +615,7 @@
void msm_map_8974_io(void);
void msm_map_8084_io(void);
void msm_map_msmkrypton_io(void);
+void msm_map_msmsamarium_io(void);
void msm_map_msm8625_io(void);
void msm_map_msm9625_io(void);
void msm_init_irq(void);
@@ -615,6 +627,7 @@
void apq8084_init_gpiomux(void);
void msm9625_init_gpiomux(void);
void msmkrypton_init_gpiomux(void);
+void msmsamarium_init_gpiomux(void);
void msm_map_mpq8092_io(void);
void mpq8092_init_gpiomux(void);
void msm_map_msm8226_io(void);
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 248c9b0..3e7e5fd 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -79,6 +79,7 @@
struct msm_camera_i2c_conf *i2c_conf;
struct msm_sensor_info_t *sensor_info;
struct msm_sensor_init_params *sensor_init_params;
+ const char *misc_regulator;
};
enum msm_camera_i2c_cmd_type {
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 0dd4957..27c6df4 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -61,8 +61,8 @@
struct regulator **regulator;
int num_regulators;
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- int **vdd_uv;
- int **vdd_ua;
+ int *vdd_uv;
+ int *vdd_ua;
int *level_votes;
int num_levels;
unsigned long cur_level;
@@ -93,9 +93,6 @@
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
-#define VDD_UV(...) ((int []){__VA_ARGS__})
-#define VDD_UA(...) ((int []){__VA_ARGS__})
-
enum handoff {
HANDOFF_ENABLED_CLK,
HANDOFF_DISABLED_CLK,
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index 1809456..fae0777 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -25,6 +25,7 @@
#define CLKFLAG_MAX 0x00000800
#define CLKFLAG_INIT_DONE 0x00001000
#define CLKFLAG_INIT_ERR 0x00002000
+#define CLKFLAG_NO_RATE_CACHE 0x00004000
struct clk_lookup;
struct clk;
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 23d204a..06f5215 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -98,6 +98,7 @@
* @halt_enabled: Set to 1 if IOMMU halt is supported in the IOMMU, 0 otherwise.
* @asid: List of ASID and their usage count (index is ASID value).
* @ctx_attach_count: Count of how many context are attached.
+ * @bus_client : Bus client needed to vote for bus bandwidth.
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -121,12 +122,14 @@
int halt_enabled;
int *asid;
unsigned int ctx_attach_count;
+ unsigned int bus_client;
};
/**
* struct iommu_access_ops - Callbacks for accessing IOMMU
* @iommu_power_on: Turn on power to unit
* @iommu_power_off: Turn off power to unit
+ * @iommu_bus_vote: Vote for bus bandwidth
* @iommu_clk_on: Turn on clks to unit
* @iommu_clk_off: Turn off clks to unit
* @iommu_lock_initialize: Initialize the remote lock
@@ -136,6 +139,8 @@
struct iommu_access_ops {
int (*iommu_power_on)(struct msm_iommu_drvdata *);
void (*iommu_power_off)(struct msm_iommu_drvdata *);
+ int (*iommu_bus_vote)(struct msm_iommu_drvdata *drvdata,
+ unsigned int vote);
int (*iommu_clk_on)(struct msm_iommu_drvdata *);
void (*iommu_clk_off)(struct msm_iommu_drvdata *);
void * (*iommu_lock_initialize)(void);
@@ -181,6 +186,22 @@
int attach_count;
};
+struct msm_iommu_context_regs {
+ uint32_t far;
+ uint32_t par;
+ uint32_t fsr;
+ uint32_t fsynr0;
+ uint32_t fsynr1;
+ uint32_t ttbr0;
+ uint32_t ttbr1;
+ uint32_t sctlr;
+ uint32_t actlr;
+ uint32_t prrr;
+ uint32_t nmrr;
+};
+
+void print_ctx_regs(struct msm_iommu_context_regs *regs);
+
/*
* Interrupt handler for the IOMMU context fault interrupt. Hooking the
* interrupt is not supported in the API yet, but this will print an error
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 349dbe7..2216183 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -89,6 +89,8 @@
struct kgsl_device_iommu_data *iommu_data;
int iommu_count;
struct msm_dcvs_core_info *core_info;
+ struct coresight_device *csdev;
+ struct coresight_platform_data *coresight_pdata;
unsigned int chipid;
};
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-samarium.h b/arch/arm/mach-msm/include/mach/msm_iomap-samarium.h
new file mode 100644
index 0000000..7a6b626
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-samarium.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ASM_ARCH_MSM_IOMAP_SAMARIUM_H
+#define __ASM_ARCH_MSM_IOMAP_SAMARIUM_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSMSAMARIUM_SHARED_RAM_PHYS 0x0FA00000
+
+#define MSMSAMARIUM_QGIC_DIST_PHYS 0xF9000000
+#define MSMSAMARIUM_QGIC_DIST_SIZE SZ_4K
+
+#define MSMSAMARIUM_TLMM_PHYS 0xFD510000
+#define MSMSAMARIUM_TLMM_SIZE SZ_16K
+
+#define MSMSAMARIUM_MPM2_PSHOLD_PHYS 0xFC4AB000
+#define MSMSAMARIUM_MPM2_PSHOLD_SIZE SZ_4K
+
+#ifdef CONFIG_DEBUG_MSMSAMARIUM_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 185958c..7b73333 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -81,16 +81,6 @@
#define MSM_LPASS_CLK_CTL_BASE IOMEM(0xFA015000) /* 4K */
#define MSM_HFPLL_BASE IOMEM(0xFA016000) /* 4K */
#define MSM_TLMM_BASE IOMEM(0xFA017000) /* 16K */
-#define MSM_SHARED_RAM_BASE IOMEM(0xFA400000) /* 2M */
-#define MSM_SIC_NON_SECURE_BASE IOMEM(0xFA600000) /* 64K */
-#define MSM_HDMI_BASE IOMEM(0xFA800000) /* 4K */
-#define MSM_RPM_BASE IOMEM(0xFA801000) /* 4K */
-#define MSM_RPM_MPM_BASE IOMEM(0xFA802000) /* 4K */
-#define MSM_QFPROM_BASE IOMEM(0xFA700000) /* 4K */
-#define MSM_L2CC_BASE IOMEM(0xFA701000) /* 4K */
-#define MSM_APCS_GLB_BASE IOMEM(0xFA702000) /* 4K */
-#define MSM_SAW2_BASE IOMEM(0xFA703000) /* 4k */
-#define MSM_SAW3_BASE IOMEM(0xFA704000) /* 4k */
#define MSM_VIC_BASE IOMEM(0xFA100000) /* 4K */
#define MSM_CSR_BASE IOMEM(0xFA101000) /* 4K */
#define MSM_GPIO1_BASE IOMEM(0xFA102000) /* 4K */
@@ -99,7 +89,16 @@
#define MSM_CFG_CTL_BASE IOMEM(0xFA105000) /* 4K */
#define MSM_CLK_CTL_SH2_BASE IOMEM(0xFA106000) /* 4K */
#define MSM_MPM2_PSHOLD_BASE IOMEM(0xFA107000) /* 4k */
-#define MSM_MDC_BASE IOMEM(0xFA400000) /* 1M */
+#define MSM_SHARED_RAM_BASE IOMEM(0xFA400000) /* 2M */
+#define MSM_SIC_NON_SECURE_BASE IOMEM(0xFA600000) /* 64K */
+#define MSM_QFPROM_BASE IOMEM(0xFA700000) /* 4K */
+#define MSM_L2CC_BASE IOMEM(0xFA701000) /* 4K */
+#define MSM_APCS_GLB_BASE IOMEM(0xFA702000) /* 4K */
+#define MSM_SAW2_BASE IOMEM(0xFA703000) /* 4k */
+#define MSM_SAW3_BASE IOMEM(0xFA704000) /* 4k */
+#define MSM_HDMI_BASE IOMEM(0xFA800000) /* 4K */
+#define MSM_RPM_BASE IOMEM(0xFA801000) /* 4K */
+#define MSM_RPM_MPM_BASE IOMEM(0xFA802000) /* 4K */
#define MSM_AD5_BASE IOMEM(0xFA900000) /* 13M (D00000)
0xFB600000 */
/* MSM9625 has unaligned imem so we need to map excess 2K virtually
@@ -137,6 +136,8 @@
#include "msm_iomap-8610.h"
#include "msm_iomap-krypton.h"
#include "msm_iomap-fsm9900.h"
+#include "msm_iomap-samarium.h"
+
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index 894379e..5dc1095 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -46,9 +46,6 @@
spinlock_t port_lock;
struct comm_mode_info mode_info;
- struct list_head incomplete;
- struct mutex incomplete_lock;
-
struct list_head port_rx_q;
struct mutex port_rx_q_lock;
char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 3bf05e6..5c8f525 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2011, 2013 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
@@ -39,6 +39,15 @@
MEMTYPE_MAX,
};
+enum {
+ SYS_MEMORY = 1, /* system memory*/
+ BOOT_REGION_MEMORY1, /* boot loader memory 1*/
+ BOOT_REGION_MEMORY2, /* boot loader memory 2,reserved*/
+ APPSBL_MEMORY, /* apps boot loader memory*/
+ APPS_MEMORY, /* apps usage memory*/
+};
+
+
void msm_reserve(void);
#define MEMTYPE_FLAGS_FIXED 0x1
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 8539dcc..6f83c53 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -42,7 +42,7 @@
struct ocmem_zone;
struct ocmem_zone_ops {
- unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+ int (*allocate) (struct ocmem_zone *, unsigned long, unsigned long *);
int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
};
@@ -197,9 +197,9 @@
int zone_active(int);
unsigned long offset_to_phys(unsigned long);
unsigned long phys_to_offset(unsigned long);
-unsigned long allocate_head(struct ocmem_zone *, unsigned long);
+int allocate_head(struct ocmem_zone *, unsigned long, unsigned long *);
int free_head(struct ocmem_zone *, unsigned long, unsigned long);
-unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
+int allocate_tail(struct ocmem_zone *, unsigned long, unsigned long *);
int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
int ocmem_notifier_init(void);
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index dc8cbaa..99bff66 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -55,6 +55,8 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmkrypton")
#define early_machine_is_fsm9900() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,fsm9900")
+#define early_machine_is_msmsamarium() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmsamarium")
#else
#define of_board_is_sim() 0
#define of_board_is_rumi() 0
@@ -73,6 +75,7 @@
#define early_machine_is_apq8084() 0
#define early_machine_is_msmkrypton() 0
#define early_machine_is_fsm9900() 0
+#define early_machine_is_msmsamarium() 0
#endif
#define PLATFORM_SUBTYPE_MDM 1
@@ -114,6 +117,7 @@
MSM_CPU_8084,
MSM_CPU_KRYPTON,
FSM_CPU_9900,
+ MSM_CPU_SAMARIUM,
};
enum pmic_model {
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index c5ad35d..3332701 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1271,6 +1271,15 @@
int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
u32 tb_sel, u32 desc_sel);
+/**
+ * Vote for or relinquish BAM DMA clock
+ *
+ * @clk_on - to turn on or turn off the clock
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_ctrl_bam_dma_clk(bool clk_on);
#else
static inline int sps_register_bam_device(const struct sps_bam_props
*bam_props, u32 *dev_handle)
@@ -1433,6 +1442,11 @@
{
return -EPERM;
}
+
+static inline int sps_ctrl_bam_dma_clk(bool clk_on)
+{
+ return -EPERM;
+}
#endif
#endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/trace_msm_low_power.h b/arch/arm/mach-msm/include/mach/trace_msm_low_power.h
similarity index 98%
rename from arch/arm/mach-msm/trace_msm_low_power.h
rename to arch/arm/mach-msm/include/mach/trace_msm_low_power.h
index 4e9da85..faa4209 100644
--- a/arch/arm/mach-msm/trace_msm_low_power.h
+++ b/arch/arm/mach-msm/include/mach/trace_msm_low_power.h
@@ -149,6 +149,6 @@
);
#endif
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_PATH mach
#define TRACE_INCLUDE_FILE trace_msm_low_power
#include <trace/define_trace.h>
diff --git a/arch/arm/mach-msm/trace_rpm_smd.h b/arch/arm/mach-msm/include/mach/trace_rpm_smd.h
similarity index 98%
rename from arch/arm/mach-msm/trace_rpm_smd.h
rename to arch/arm/mach-msm/include/mach/trace_rpm_smd.h
index eff4860..1b019d8 100644
--- a/arch/arm/mach-msm/trace_rpm_smd.h
+++ b/arch/arm/mach-msm/include/mach/trace_rpm_smd.h
@@ -74,6 +74,6 @@
);
#endif
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_PATH mach
#define TRACE_INCLUDE_FILE trace_rpm_smd
#include <trace/define_trace.h>
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index da7c039..bc76f56 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -101,6 +101,7 @@
* @desc_mem_buf: descriptor fifo buffer.
* @event: event for wakeup.
* @enabled: true if pipe is enabled.
+* @ipa_clnt_hdl : pipe handle to ipa api.
* @priv: private data to return upon activity_notify
* or inactivity_notify callbacks.
* @activity_notify: callback to invoke on activity on one of the in pipes.
@@ -125,6 +126,8 @@
struct sps_mem_buffer desc_mem_buf;
struct usb_bam_event_info event;
bool enabled;
+ bool suspended;
+ int ipa_clnt_hdl;
void *priv;
int (*activity_notify)(void *priv);
int (*inactivity_notify)(void *priv);
@@ -195,6 +198,14 @@
struct usb_bam_connect_ipa_params *ipa_params);
/**
+ * Wait for Consumer granted from Resource Manager.
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params);
+/**
* Register a wakeup callback from peer BAM.
*
* @idx - Connection index.
@@ -221,6 +232,39 @@
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
/**
+ * Register callbacks for start/stop of transfers.
+ *
+ * @start - the callback function that will be called in USB
+ * driver to start transfers
+ * @stop - the callback function that will be called in USB
+ * driver to stop transfers
+ *
+ * @param - context that the caller can supply
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param);
+
+/**
+ * Start usb suspend sequence
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params);
+
+/**
+ * Start usb resume sequence
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params);
+/**
* Disconnect USB-to-Periperal SPS connection.
*
* @idx - Connection index.
@@ -315,6 +359,12 @@
return -ENODEV;
}
+static inline void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params)
+{
+ return;
+}
+
static inline int usb_bam_register_wake_cb(u8 idx,
int (*callback)(void *), void* param)
{
@@ -327,6 +377,20 @@
return -ENODEV;
}
+static inline int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param)
+{
+ return -ENODEV;
+}
+
+static inline void usb_bam_suspend(
+ struct usb_bam_connect_ipa_params *ipa_params){}
+
+static inline void usb_bam_resume(
+ struct usb_bam_connect_ipa_params *ipa_params) {}
+
static inline int usb_bam_disconnect_pipe(u8 idx)
{
return -ENODEV;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 099862f..7fb2c88 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -69,7 +69,6 @@
MSM_CHIP_DEVICE(GPIO2, MSM7XXX),
MSM_CHIP_DEVICE(CLK_CTL, MSM7XXX),
MSM_CHIP_DEVICE(AD5, MSM7XXX),
- MSM_CHIP_DEVICE(MDC, MSM7XXX),
#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
defined(CONFIG_DEBUG_MSM_UART3)
MSM_DEVICE(DEBUG_UART),
@@ -117,7 +116,6 @@
MSM_DEVICE(SIRC),
MSM_DEVICE(SCPLL),
MSM_DEVICE(AD5),
- MSM_DEVICE(MDC),
MSM_DEVICE(TCSR),
#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
defined(CONFIG_DEBUG_MSM_UART3)
@@ -353,7 +351,6 @@
MSM_CHIP_DEVICE(CLK_CTL, MSM7X30),
MSM_CHIP_DEVICE(CLK_CTL_SH2, MSM7X30),
MSM_CHIP_DEVICE(AD5, MSM7X30),
- MSM_CHIP_DEVICE(MDC, MSM7X30),
MSM_CHIP_DEVICE(ACC0, MSM7X30),
MSM_CHIP_DEVICE(SAW0, MSM7X30),
MSM_CHIP_DEVICE(APCS_GCC, MSM7X30),
@@ -476,7 +473,6 @@
MSM_CHIP_DEVICE(SAW2, MSM8625),
MSM_CHIP_DEVICE(SAW3, MSM8625),
MSM_CHIP_DEVICE(AD5, MSM7XXX),
- MSM_CHIP_DEVICE(MDC, MSM7XXX),
#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
defined(CONFIG_DEBUG_MSM_UART3)
MSM_DEVICE(DEBUG_UART),
@@ -614,3 +610,26 @@
of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MSM8610 */
+
+#ifdef CONFIG_ARCH_MSMSAMARIUM
+static struct map_desc msmsamarium_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSMSAMARIUM),
+ MSM_CHIP_DEVICE(TLMM, MSMSAMARIUM),
+ MSM_CHIP_DEVICE(MPM2_PSHOLD, MSMSAMARIUM),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+#if defined(CONFIG_DEBUG_MSMSAMARIUM_UART) || defined(CONFIG_DEBUG_MSM8974_UART)
+ MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_msmsamarium_io(void)
+{
+ msm_shared_ram_phys = MSMSAMARIUM_SHARED_RAM_PHYS;
+ msm_map_io(msmsamarium_io_desc, ARRAY_SIZE(msmsamarium_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_MSMSAMARIUM */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index f4ac37e..12f5a8e 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -570,12 +570,14 @@
goto out;
}
ctx = msm_iommu_get_ctx(name);
- if (!ctx) {
- pr_err("Unable to find context %s\n", name);
- ret_val = -EINVAL;
+ if (IS_ERR(ctx)) {
+ ret_val = PTR_ERR(ctx);
goto out;
}
- iommu_group_add_device(group, ctx);
+
+ ret_val = iommu_group_add_device(group, ctx);
+ if (ret_val)
+ goto out;
}
out:
return ret_val;
@@ -590,7 +592,7 @@
struct msm_iova_layout l;
struct msm_iova_partition *part = 0;
struct iommu_domain *domain = 0;
- unsigned int *addr_array;
+ unsigned int *addr_array = 0;
unsigned int array_size;
int domain_no;
int secure_domain;
@@ -661,11 +663,46 @@
iommu_group_set_iommudata(group, domain, NULL);
free_mem:
+ kfree(addr_array);
kfree(part);
out:
return ret_val;
}
+static int __msm_group_get_domain(struct device *dev, void *data)
+{
+ struct msm_iommu_data_entry *list_entry;
+ struct list_head *dev_list = data;
+ int ret_val = 0;
+
+ list_entry = kmalloc(sizeof(*list_entry), GFP_KERNEL);
+ if (list_entry) {
+ list_entry->data = dev;
+ list_add(&list_entry->list, dev_list);
+ } else {
+ ret_val = -ENOMEM;
+ }
+
+ return ret_val;
+}
+
+static void __msm_iommu_group_remove_device(struct iommu_group *grp)
+{
+ struct msm_iommu_data_entry *tmp;
+ struct msm_iommu_data_entry *list_entry;
+ struct list_head dev_list;
+
+ INIT_LIST_HEAD(&dev_list);
+ iommu_group_for_each_dev(grp, &dev_list, __msm_group_get_domain);
+
+ list_for_each_entry_safe(list_entry, tmp, &dev_list, list) {
+ iommu_group_remove_device(list_entry->data);
+ list_del(&list_entry->list);
+ kfree(list_entry);
+ }
+}
+
+
static int iommu_domain_parse_dt(const struct device_node *dt_node)
{
struct device_node *node;
@@ -674,13 +711,30 @@
int ret_val = 0;
struct iommu_group *group = 0;
const char *name;
+ struct msm_iommu_data_entry *grp_list_entry;
+ struct msm_iommu_data_entry *tmp;
+ struct list_head iommu_group_list;
+ INIT_LIST_HEAD(&iommu_group_list);
for_each_child_of_node(dt_node, node) {
group = iommu_group_alloc();
if (IS_ERR(group)) {
ret_val = PTR_ERR(group);
- goto out;
+ group = 0;
+ goto free_group;
}
+
+ /* This is only needed to clean up memory if something fails */
+ grp_list_entry = kmalloc(sizeof(*grp_list_entry),
+ GFP_KERNEL);
+ if (grp_list_entry) {
+ grp_list_entry->data = group;
+ list_add(&grp_list_entry->list, &iommu_group_list);
+ } else {
+ ret_val = -ENOMEM;
+ goto free_group;
+ }
+
if (of_property_read_string(node, "label", &name)) {
ret_val = -EINVAL;
goto free_group;
@@ -696,7 +750,6 @@
ret_val = find_and_add_contexts(group, node, num_contexts);
if (ret_val) {
- ret_val = -EINVAL;
goto free_group;
}
ret_val = create_and_add_domain(group, node, name);
@@ -704,9 +757,33 @@
ret_val = -EINVAL;
goto free_group;
}
+
+ /* Remove reference to the group that is taken when the group
+ * is allocated. This will ensure that when all the devices in
+ * the group are removed the group will be released.
+ */
+ iommu_group_put(group);
}
+
+ list_for_each_entry_safe(grp_list_entry, tmp, &iommu_group_list, list) {
+ list_del(&grp_list_entry->list);
+ kfree(grp_list_entry);
+ }
+ goto out;
+
free_group:
- /* No iommu_group_free() function */
+ list_for_each_entry_safe(grp_list_entry, tmp, &iommu_group_list, list) {
+ struct iommu_domain *d;
+
+ d = iommu_group_get_iommudata(grp_list_entry->data);
+ if (d)
+ msm_unregister_domain(d);
+
+ __msm_iommu_group_remove_device(grp_list_entry->data);
+ list_del(&grp_list_entry->list);
+ kfree(grp_list_entry);
+ }
+ iommu_group_put(group);
out:
return ret_val;
}
diff --git a/arch/arm/mach-msm/ipc_logging.c b/arch/arm/mach-msm/ipc_logging.c
index 1260a1a..280f237 100644
--- a/arch/arm/mach-msm/ipc_logging.c
+++ b/arch/arm/mach-msm/ipc_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -32,7 +32,7 @@
#include "ipc_logging.h"
static LIST_HEAD(ipc_log_context_list);
-DEFINE_SPINLOCK(ipc_log_context_list_lock);
+DEFINE_RWLOCK(ipc_log_context_list_lock);
static atomic_t next_log_id = ATOMIC_INIT(0);
static struct ipc_log_page *get_first_page(struct ipc_log_context *ilctxt)
@@ -140,7 +140,7 @@
return;
}
- spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+ read_lock_irqsave(&ipc_log_context_list_lock, flags);
spin_lock(&ilctxt->ipc_log_context_lock);
while (ilctxt->write_avail < ectxt->offset)
msg_read(ilctxt, NULL);
@@ -165,7 +165,7 @@
ilctxt->write_avail -= ectxt->offset;
complete(&ilctxt->read_avail);
spin_unlock(&ilctxt->ipc_log_context_lock);
- spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
}
EXPORT_SYMBOL(ipc_log_write);
@@ -471,13 +471,13 @@
if (!df_info)
return -ENOSPC;
- spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+ read_lock_irqsave(&ipc_log_context_list_lock, flags);
spin_lock(&ilctxt->ipc_log_context_lock);
df_info->type = type;
df_info->dfunc = dfunc;
list_add_tail(&df_info->list, &ilctxt->dfunc_info_list);
spin_unlock(&ilctxt->ipc_log_context_lock);
- spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
return 0;
}
EXPORT_SYMBOL(add_deserialization_func);
@@ -528,9 +528,9 @@
create_ctx_debugfs(ctxt, mod_name);
- spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+ write_lock_irqsave(&ipc_log_context_list_lock, flags);
list_add_tail(&ctxt->list, &ipc_log_context_list);
- spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ write_unlock_irqrestore(&ipc_log_context_list_lock, flags);
return (void *)ctxt;
release_ipc_log_context:
diff --git a/arch/arm/mach-msm/ipc_logging.h b/arch/arm/mach-msm/ipc_logging.h
index 0eb82a5..36b4171 100644
--- a/arch/arm/mach-msm/ipc_logging.h
+++ b/arch/arm/mach-msm/ipc_logging.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -65,7 +65,7 @@
#define IS_MSG_TYPE(x) (((x) > TSV_TYPE_MSG_START) && \
((x) < TSV_TYPE_MSG_END))
-extern spinlock_t ipc_log_context_list_lock;
+extern rwlock_t ipc_log_context_list_lock;
extern int msg_read(struct ipc_log_context *ilctxt,
struct encode_context *ectxt);
diff --git a/arch/arm/mach-msm/ipc_logging_debug.c b/arch/arm/mach-msm/ipc_logging_debug.c
index ff947ef..246fb99 100644
--- a/arch/arm/mach-msm/ipc_logging_debug.c
+++ b/arch/arm/mach-msm/ipc_logging_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -62,7 +62,7 @@
dctxt.output_format = OUTPUT_DEBUGFS;
dctxt.buff = buff;
dctxt.size = size;
- spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+ read_lock_irqsave(&ipc_log_context_list_lock, flags);
spin_lock(&ilctxt->ipc_log_context_lock);
while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
!is_ilctxt_empty(ilctxt)) {
@@ -70,19 +70,19 @@
deserialize_func = get_deserialization_func(ilctxt,
ectxt.hdr.type);
spin_unlock(&ilctxt->ipc_log_context_lock);
- spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
if (deserialize_func)
deserialize_func(&ectxt, &dctxt);
else
pr_err("%s: unknown message 0x%x\n",
__func__, ectxt.hdr.type);
- spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+ read_lock_irqsave(&ipc_log_context_list_lock, flags);
spin_lock(&ilctxt->ipc_log_context_lock);
}
if ((size - dctxt.size) == 0)
init_completion(&ilctxt->read_avail);
spin_unlock(&ilctxt->ipc_log_context_lock);
- spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
return size - dctxt.size;
}
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index aee691f..573b9a3 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -115,7 +115,6 @@
#define SRV_HASH_SIZE 32
static struct list_head server_list[SRV_HASH_SIZE];
static DEFINE_MUTEX(server_list_lock);
-static wait_queue_head_t newserver_wait;
struct msm_ipc_server {
struct list_head list;
@@ -182,9 +181,6 @@
static DEFINE_MUTEX(routing_table_lock);
static int routing_table_inited;
-static LIST_HEAD(msm_ipc_board_dev_list);
-static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
-
static void do_read_data(struct work_struct *work);
#define RR_STATE_IDLE 0
@@ -476,23 +472,44 @@
kfree(skb_head);
}
+static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
+ struct rr_packet *pkt, int clone)
+{
+ struct rr_packet *temp_pkt = pkt;
+
+ if (unlikely(!port_ptr || !pkt))
+ return -EINVAL;
+
+ if (clone) {
+ temp_pkt = clone_pkt(pkt);
+ if (!temp_pkt) {
+ pr_err("%s: Error cloning packet for port %08x:%08x\n",
+ __func__, port_ptr->this_port.node_id,
+ port_ptr->this_port.port_id);
+ return -ENOMEM;
+ }
+ }
+
+ mutex_lock(&port_ptr->port_rx_q_lock);
+ wake_lock(&port_ptr->port_rx_wake_lock);
+ list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
+ wake_up(&port_ptr->port_rx_wait_q);
+ if (port_ptr->notify)
+ port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
+ mutex_unlock(&port_ptr->port_rx_q_lock);
+ return 0;
+}
+
static int post_control_ports(struct rr_packet *pkt)
{
struct msm_ipc_port *port_ptr;
- struct rr_packet *cloned_pkt;
if (!pkt)
return -EINVAL;
mutex_lock(&control_ports_lock);
- list_for_each_entry(port_ptr, &control_ports, list) {
- mutex_lock(&port_ptr->port_rx_q_lock);
- cloned_pkt = clone_pkt(pkt);
- wake_lock(&port_ptr->port_rx_wake_lock);
- list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
- wake_up(&port_ptr->port_rx_wait_q);
- mutex_unlock(&port_ptr->port_rx_q_lock);
- }
+ list_for_each_entry(port_ptr, &control_ports, list)
+ post_pkt_to_port(port_ptr, pkt, 1);
mutex_unlock(&control_ports_lock);
return 0;
}
@@ -565,8 +582,6 @@
}
spin_lock_init(&port_ptr->port_lock);
- INIT_LIST_HEAD(&port_ptr->incomplete);
- mutex_init(&port_ptr->incomplete_lock);
INIT_LIST_HEAD(&port_ptr->port_rx_q);
mutex_init(&port_ptr->port_rx_q_lock);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
@@ -736,27 +751,14 @@
{
struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
struct msm_ipc_port *local_port;
- struct rr_packet *cloned_pkt;
list_for_each_entry_safe(rtx_port, tmp_rtx_port,
&rport_ptr->resume_tx_port_list, list) {
mutex_lock(&local_ports_lock);
local_port =
msm_ipc_router_lookup_local_port(rtx_port->port_id);
- if (local_port) {
- cloned_pkt = clone_pkt(pkt);
- if (cloned_pkt) {
- mutex_lock(&local_port->port_rx_q_lock);
- list_add_tail(&cloned_pkt->list,
- &local_port->port_rx_q);
- wake_up(&local_port->port_rx_wait_q);
- mutex_unlock(&local_port->port_rx_q_lock);
- } else {
- pr_err("%s: Clone_pkt failed for %08x:%08x\n",
- __func__, local_port->this_port.node_id,
- local_port->this_port.port_id);
- }
- }
+ if (local_port)
+ post_pkt_to_port(local_port, pkt, 1);
mutex_unlock(&local_ports_lock);
list_del(&rtx_port->list);
kfree(rtx_port);
@@ -1646,16 +1648,157 @@
return rc;
}
+static int process_resume_tx_msg(union rr_control_msg *msg,
+ struct rr_packet *pkt)
+{
+ struct msm_ipc_router_remote_port *rport_ptr;
+
+ RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+
+ rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+ msg->cli.port_id);
+ if (!rport_ptr) {
+ pr_err("%s: Unable to resume client\n", __func__);
+ return -ENODEV;
+ }
+ mutex_lock(&rport_ptr->quota_lock);
+ rport_ptr->tx_quota_cnt = 0;
+ post_resume_tx(rport_ptr, pkt);
+ mutex_unlock(&rport_ptr->quota_lock);
+ return 0;
+}
+
+static int process_new_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
+ union rr_control_msg *msg, struct rr_packet *pkt)
+{
+ struct msm_ipc_routing_table_entry *rt_entry;
+ struct msm_ipc_server *server;
+ struct msm_ipc_router_remote_port *rport_ptr;
+
+ if (msg->srv.instance == 0) {
+ pr_err("%s: Server %08x create rejected, version = 0\n",
+ __func__, msg->srv.service);
+ return -EINVAL;
+ }
+
+ RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n", msg->srv.node_id,
+ msg->srv.port_id, msg->srv.service, msg->srv.instance);
+ /*
+ * Find the entry from Routing Table corresponding to Node ID.
+ * Under SSR, an entry will be found. When the subsystem hosting
+ * service is not adjacent, an entry will not be found and hence
+ * allocate an entry. Update the entry with the Node ID that it
+ * corresponds to and the XPRT through which it can be reached.
+ */
+ mutex_lock(&routing_table_lock);
+ rt_entry = lookup_routing_table(msg->srv.node_id);
+ if (!rt_entry) {
+ rt_entry = alloc_routing_table_entry(msg->srv.node_id);
+ if (!rt_entry) {
+ mutex_unlock(&routing_table_lock);
+ pr_err("%s: rt_entry allocation failed\n", __func__);
+ return -ENOMEM;
+ }
+ mutex_lock(&rt_entry->lock);
+ rt_entry->neighbor_node_id = xprt_info->remote_node_id;
+ rt_entry->xprt_info = xprt_info;
+ mutex_unlock(&rt_entry->lock);
+ add_routing_table_entry(rt_entry);
+ }
+ mutex_unlock(&routing_table_lock);
+
+ /*
+ * If the service does not exist already in the database, create and
+ * store the service info. Create a remote port structure in which
+ * the service is hosted and cache the security rule for the service
+ * in that remote port structure.
+ */
+ mutex_lock(&server_list_lock);
+ server = msm_ipc_router_lookup_server(msg->srv.service,
+ msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
+ if (!server) {
+ server = msm_ipc_router_create_server(
+ msg->srv.service, msg->srv.instance,
+ msg->srv.node_id, msg->srv.port_id, xprt_info);
+ if (!server) {
+ mutex_unlock(&server_list_lock);
+ pr_err("%s: Server Create failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (!msm_ipc_router_lookup_remote_port(
+ msg->srv.node_id, msg->srv.port_id)) {
+ rport_ptr = msm_ipc_router_create_remote_port(
+ msg->srv.node_id, msg->srv.port_id);
+ if (!rport_ptr) {
+ mutex_unlock(&server_list_lock);
+ return -ENOMEM;
+ }
+ rport_ptr->sec_rule = msm_ipc_get_security_rule(
+ msg->srv.service,
+ msg->srv.instance);
+ }
+ }
+ mutex_unlock(&server_list_lock);
+
+ /*
+ * Relay the new server message to other subsystems that do not belong
+ * to the cluster from which this message is received. Notify the
+ * local clients waiting for this service.
+ */
+ relay_msg(xprt_info, pkt);
+ post_control_ports(pkt);
+ return 0;
+}
+
+static int process_rmv_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
+ union rr_control_msg *msg, struct rr_packet *pkt)
+{
+ struct msm_ipc_server *server;
+
+ RR("o REMOVE_SERVER service=%08x:%d\n",
+ msg->srv.service, msg->srv.instance);
+ mutex_lock(&server_list_lock);
+ server = msm_ipc_router_lookup_server(msg->srv.service,
+ msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
+ if (server) {
+ msm_ipc_router_destroy_server(server, msg->srv.node_id,
+ msg->srv.port_id);
+ /*
+ * Relay the new server message to other subsystems that do not
+ * belong to the cluster from which this message is received.
+ * Notify the local clients communicating with the service.
+ */
+ relay_msg(xprt_info, pkt);
+ post_control_ports(pkt);
+ }
+ mutex_unlock(&server_list_lock);
+ return 0;
+}
+
+static int process_rmv_client_msg(struct msm_ipc_router_xprt_info *xprt_info,
+ union rr_control_msg *msg, struct rr_packet *pkt)
+{
+ struct msm_ipc_router_remote_port *rport_ptr;
+
+ RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+ rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+ msg->cli.port_id);
+ if (rport_ptr)
+ msm_ipc_router_destroy_remote_port(rport_ptr);
+
+ relay_msg(xprt_info, pkt);
+ post_control_ports(pkt);
+ return 0;
+}
+
static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
struct rr_packet *pkt)
{
union rr_control_msg *msg;
- struct msm_ipc_router_remote_port *rport_ptr;
int rc = 0;
struct sk_buff *temp_ptr;
struct rr_header *hdr;
- struct msm_ipc_server *server;
- struct msm_ipc_routing_table_entry *rt_entry;
if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
@@ -1679,115 +1822,17 @@
case IPC_ROUTER_CTRL_CMD_HELLO:
rc = process_hello_msg(xprt_info, hdr);
break;
-
case IPC_ROUTER_CTRL_CMD_RESUME_TX:
- RR("o RESUME_TX id=%d:%08x\n",
- msg->cli.node_id, msg->cli.port_id);
-
- rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
- msg->cli.port_id);
- if (!rport_ptr) {
- pr_err("%s: Unable to resume client\n", __func__);
- break;
- }
- mutex_lock(&rport_ptr->quota_lock);
- rport_ptr->tx_quota_cnt = 0;
- post_resume_tx(rport_ptr, pkt);
- mutex_unlock(&rport_ptr->quota_lock);
+ rc = process_resume_tx_msg(msg, pkt);
break;
-
case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
- if (msg->srv.instance == 0) {
- pr_err(
- "rpcrouter: Server create rejected, version = 0, "
- "service = %08x\n", msg->srv.service);
- break;
- }
-
- RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
- msg->srv.node_id, msg->srv.port_id,
- msg->srv.service, msg->srv.instance);
-
- mutex_lock(&routing_table_lock);
- rt_entry = lookup_routing_table(msg->srv.node_id);
- if (!rt_entry) {
- rt_entry = alloc_routing_table_entry(msg->srv.node_id);
- if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
- pr_err("%s: rt_entry allocation failed\n",
- __func__);
- return -ENOMEM;
- }
- mutex_lock(&rt_entry->lock);
- rt_entry->neighbor_node_id = xprt_info->remote_node_id;
- rt_entry->xprt_info = xprt_info;
- mutex_unlock(&rt_entry->lock);
- add_routing_table_entry(rt_entry);
- }
- mutex_unlock(&routing_table_lock);
-
- mutex_lock(&server_list_lock);
- server = msm_ipc_router_lookup_server(msg->srv.service,
- msg->srv.instance,
- msg->srv.node_id,
- msg->srv.port_id);
- if (!server) {
- server = msm_ipc_router_create_server(
- msg->srv.service, msg->srv.instance,
- msg->srv.node_id, msg->srv.port_id, xprt_info);
- if (!server) {
- mutex_unlock(&server_list_lock);
- pr_err("%s: Server Create failed\n", __func__);
- return -ENOMEM;
- }
-
- if (!msm_ipc_router_lookup_remote_port(
- msg->srv.node_id, msg->srv.port_id)) {
- rport_ptr = msm_ipc_router_create_remote_port(
- msg->srv.node_id, msg->srv.port_id);
- if (!rport_ptr)
- pr_err("%s: Remote port create "
- "failed\n", __func__);
- else
- rport_ptr->sec_rule =
- msm_ipc_get_security_rule(
- msg->srv.service,
- msg->srv.instance);
- }
- wake_up(&newserver_wait);
- }
- mutex_unlock(&server_list_lock);
-
- relay_msg(xprt_info, pkt);
- post_control_ports(pkt);
+ rc = process_new_server_msg(xprt_info, msg, pkt);
break;
case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
- RR("o REMOVE_SERVER service=%08x:%d\n",
- msg->srv.service, msg->srv.instance);
- mutex_lock(&server_list_lock);
- server = msm_ipc_router_lookup_server(msg->srv.service,
- msg->srv.instance,
- msg->srv.node_id,
- msg->srv.port_id);
- if (server) {
- msm_ipc_router_destroy_server(server,
- msg->srv.node_id,
- msg->srv.port_id);
- relay_msg(xprt_info, pkt);
- post_control_ports(pkt);
- }
- mutex_unlock(&server_list_lock);
+ rc = process_rmv_server_msg(xprt_info, msg, pkt);
break;
case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
- RR("o REMOVE_CLIENT id=%d:%08x\n",
- msg->cli.node_id, msg->cli.port_id);
- rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
- msg->cli.port_id);
- if (rport_ptr)
- msm_ipc_router_destroy_remote_port(rport_ptr);
-
- relay_msg(xprt_info, pkt);
- post_control_ports(pkt);
+ rc = process_rmv_client_msg(xprt_info, msg, pkt);
break;
case IPC_ROUTER_CTRL_CMD_PING:
/* No action needed for ping messages received */
@@ -1901,14 +1946,7 @@
}
}
- mutex_lock(&port_ptr->port_rx_q_lock);
- wake_lock(&port_ptr->port_rx_wake_lock);
- list_add_tail(&pkt->list, &port_ptr->port_rx_q);
- wake_up(&port_ptr->port_rx_wait_q);
- if (port_ptr->notify)
- port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
- port_ptr->priv);
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ post_pkt_to_port(port_ptr, pkt, 0);
mutex_unlock(&local_ports_lock);
process_done:
@@ -2082,12 +2120,8 @@
return -ENODEV;
}
- mutex_lock(&port_ptr->port_rx_q_lock);
- wake_lock(&port_ptr->port_rx_wake_lock);
- list_add_tail(&pkt->list, &port_ptr->port_rx_q);
ret_len = pkt->length;
- wake_up(&port_ptr->port_rx_wait_q);
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ post_pkt_to_port(port_ptr, pkt, 0);
update_comm_mode_info(&src->mode_info, NULL);
mutex_unlock(&local_ports_lock);
@@ -2962,9 +2996,14 @@
D("open event for '%s'\n", xprt->name);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
GFP_ATOMIC);
- xprt_work->xprt = xprt;
- INIT_WORK(&xprt_work->work, xprt_open_worker);
- queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ if (xprt_work) {
+ xprt_work->xprt = xprt;
+ INIT_WORK(&xprt_work->work, xprt_open_worker);
+ queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ } else {
+ pr_err("%s: malloc failure - Couldn't notify OPEN event",
+ __func__);
+ }
break;
case IPC_ROUTER_XPRT_EVENT_CLOSE:
@@ -2972,9 +3011,14 @@
atomic_inc(&pending_close_count);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
GFP_ATOMIC);
- xprt_work->xprt = xprt;
- INIT_WORK(&xprt_work->work, xprt_close_worker);
- queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ if (xprt_work) {
+ xprt_work->xprt = xprt;
+ INIT_WORK(&xprt_work->work, xprt_close_worker);
+ queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ } else {
+ pr_err("%s: malloc failure - Couldn't notify CLOSE event",
+ __func__);
+ }
break;
}
@@ -3070,7 +3114,6 @@
}
mutex_unlock(&routing_table_lock);
- init_waitqueue_head(&newserver_wait);
init_waitqueue_head(&subsystem_restart_wait);
ret = msm_ipc_router_init_sockets();
if (ret < 0)
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 624a27c..1d9c539 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -23,11 +23,12 @@
#include <linux/tick.h>
#include <mach/mpm.h>
#include <mach/rpm-smd.h>
+#include <mach/trace_msm_low_power.h>
#include "spm.h"
#include "lpm_resources.h"
#include "rpm-notifier.h"
#include "idle.h"
-#include "trace_msm_low_power.h"
+
/*Debug Definitions*/
enum {
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 1680993..d7d3081 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -384,7 +384,28 @@
return 0;
}
-/* This function scans the device tree to populate the memory hole table */
+/* Function to remove any meminfo blocks which are of size zero */
+static void merge_meminfo(void)
+{
+ int i = 0;
+
+ while (i < meminfo.nr_banks) {
+ struct membank *bank = &meminfo.bank[i];
+
+ if (bank->size == 0) {
+ memmove(bank, bank + 1,
+ (meminfo.nr_banks - i) * sizeof(*bank));
+ meminfo.nr_banks--;
+ continue;
+ }
+ i++;
+ }
+}
+
+/*
+ * Function to scan the device tree and adjust the meminfo table to
+ * reflect the memory holes.
+ */
int __init dt_scan_for_memory_hole(unsigned long node, const char *uname,
int depth, void *data)
{
@@ -413,16 +434,6 @@
hole_start = be32_to_cpu(memory_remove_prop[0]);
hole_size = be32_to_cpu(memory_remove_prop[1]);
- if (hole_start + hole_size <= MAX_HOLE_ADDRESS) {
- if (memory_hole_start == 0 && memory_hole_end == 0) {
- memory_hole_start = hole_start;
- memory_hole_end = hole_start + hole_size;
- } else if ((memory_hole_end - memory_hole_start)
- <= hole_size) {
- memory_hole_start = hole_start;
- memory_hole_end = hole_start + hole_size;
- }
- }
adjust_meminfo(hole_start, hole_size);
}
@@ -452,6 +463,7 @@
bank[1].start = (start + size);
bank[1].size -= (bank->size + size);
bank[1].highmem = 0;
+ merge_meminfo();
}
}
}
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 97195e3..de90427 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -20,12 +20,44 @@
#include <mach/msm_memtypes.h>
#include <mach/socinfo.h>
#include <mach/msm_smem.h>
-#include "smd_private.h"
#if defined(CONFIG_ARCH_MSM8960)
#include "rpm_resources.h"
#endif
+struct smem_ram_ptn {
+ char name[16];
+ unsigned start;
+ unsigned size;
+
+ /* RAM Partition attribute: READ_ONLY, READWRITE etc. */
+ unsigned attr;
+
+ /* RAM Partition category: EBI0, EBI1, IRAM, IMEM */
+ unsigned category;
+
+ /* RAM Partition domain: APPS, MODEM, APPS & MODEM (SHARED) etc. */
+ unsigned domain;
+
+ /* RAM Partition type: system, bootloader, appsboot, apps etc. */
+ unsigned type;
+
+ /* reserved for future expansion without changing version number */
+ unsigned reserved2, reserved3, reserved4, reserved5;
+} __attribute__ ((__packed__));
+
+
+struct smem_ram_ptable {
+ #define _SMEM_RAM_PTABLE_MAGIC_1 0x9DA5E0A8
+ #define _SMEM_RAM_PTABLE_MAGIC_2 0xAF9EC4E2
+ unsigned magic[2];
+ unsigned version;
+ unsigned reserved1;
+ unsigned len;
+ struct smem_ram_ptn parts[32];
+ unsigned buf;
+} __attribute__ ((__packed__));
+
static struct mem_region_t {
u64 start;
u64 size;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index f05b381..d531aaa 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1460,7 +1460,7 @@
* boundary in future
*/
wmb();
- set_qos_mode(binfo->base, mas_index, 0, 1, 1);
+ set_qos_mode(binfo->base, mas_index, 1, 1, 1);
break;
case BIMC_QOS_MODE_BYPASS:
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 2c7ceab..62da5ac 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
- int i;
+ long rounded_rate;
sel_cdata = fabric->cdata[ctx];
@@ -379,8 +379,17 @@
}
/* Enable clocks before accessing QoS registers */
- for (i = 0; i < NUM_CTX; i++)
- clk_prepare_enable(fabric->info.nodeclk[i].clk);
+ if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
+ rounded_rate = clk_round_rate(fabric->
+ info.nodeclk[DUAL_CTX].clk, 1);
+ if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
+ rounded_rate))
+ MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
+ fabric->fabdev.id, rounded_rate);
+
+ clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
if (info->iface_clk.clk)
clk_prepare_enable(info->iface_clk.clk);
@@ -392,8 +401,9 @@
master_tiers, add_bw);
/* Disable clocks after accessing QoS registers */
- for (i = 0; i < NUM_CTX; i++)
- clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+ if (fabric->info.nodeclk[DUAL_CTX].clk &&
+ fabric->info.nodeclk[DUAL_CTX].rate == 0)
+ clk_disable_unprepare(fabric->info.nodeclk[DUAL_CTX].clk);
if (info->iface_clk.clk) {
MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
index 203bb60..a0ff9f9 100644
--- a/arch/arm/mach-msm/ocmem_allocator.c
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -36,24 +36,22 @@
reserve: Enable libgenpool to simulate tail allocations
*/
-unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
+int allocate_head(struct ocmem_zone *z, unsigned long size,
+ unsigned long *offset)
{
+ *offset = gen_pool_alloc(z->z_pool, size);
- unsigned long offset;
-
- offset = gen_pool_alloc(z->z_pool, size);
-
- if (!offset)
+ if (!(*offset))
return -ENOMEM;
z->z_head += size;
z->z_free -= size;
- return offset;
+ return 0;
}
-unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
+int allocate_tail(struct ocmem_zone *z, unsigned long size,
+ unsigned long *offset)
{
- unsigned long offset;
unsigned long reserve;
unsigned long head;
@@ -63,17 +61,17 @@
reserve = z->z_tail - z->z_head - size;
if (reserve) {
head = gen_pool_alloc(z->z_pool, reserve);
- offset = gen_pool_alloc(z->z_pool, size);
+ *offset = gen_pool_alloc(z->z_pool, size);
gen_pool_free(z->z_pool, head, reserve);
} else
- offset = gen_pool_alloc(z->z_pool, size);
+ *offset = gen_pool_alloc(z->z_pool, size);
- if (!offset)
+ if (!(*offset))
return -ENOMEM;
z->z_tail -= size;
z->z_free -= size;
- return offset;
+ return 0;
}
int free_head(struct ocmem_zone *z, unsigned long offset,
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 9b18c59..153864d 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -759,7 +759,7 @@
return -EINVAL;
}
-#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+#if defined(CONFIG_MSM_OCMEM_DEBUG_ALWAYS_ON)
static int ocmem_core_set_default_state(void)
{
int rc = 0;
@@ -775,7 +775,14 @@
return 0;
}
+#else
+static int ocmem_core_set_default_state(void)
+{
+ return 0;
+}
+#endif
+#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
/* Initializes a region to be turned ON in wide mode */
static int ocmem_region_set_default_state(unsigned int r_num)
{
@@ -800,15 +807,9 @@
{
return 0;
}
-
-static int ocmem_core_set_default_state(void)
-{
- return 0;
-}
#endif
#if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
-
static int read_hw_region_state(unsigned region_num)
{
int state;
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index a14b960..21c4e1e 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -724,6 +724,7 @@
bool retry;
struct ocmem_region *spanned_r = NULL;
struct ocmem_region *overlap_r = NULL;
+ int rc = 0;
struct ocmem_req *matched_req = NULL;
struct ocmem_region *matched_region = NULL;
@@ -767,9 +768,10 @@
if (overlap_r == NULL) {
/* no conflicting regions, schedule this region */
zone->z_ops->free(zone, curr_start, curr_sz);
- alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
+ rc = zone->z_ops->allocate(zone, curr_sz + growth_sz,
+ &alloc_addr);
- if (alloc_addr < 0) {
+ if (rc) {
pr_err("ocmem: zone allocation operation failed\n");
goto internal_error;
}
@@ -933,6 +935,7 @@
struct ocmem_region *matched_region = NULL;
struct ocmem_region *region = NULL;
unsigned long alloc_addr = 0x0;
+ int rc = 0;
struct ocmem_zone *zone = get_zone(owner);
@@ -957,9 +960,9 @@
goto internal_error;
}
- alloc_addr = zone->z_ops->allocate(zone, new_sz);
+ rc = zone->z_ops->allocate(zone, new_sz, &alloc_addr);
- if (alloc_addr < 0) {
+ if (rc) {
pr_err("Zone Allocation operation failed\n");
goto internal_error;
}
@@ -1032,6 +1035,7 @@
enum client_prio prio = req->prio;
unsigned long alloc_addr = 0x0;
bool retry;
+ int rc = 0;
struct ocmem_region *spanned_r = NULL;
struct ocmem_region *overlap_r = NULL;
@@ -1078,9 +1082,9 @@
if (overlap_r == NULL) {
/* no conflicting regions, schedule this region */
- alloc_addr = zone->z_ops->allocate(zone, sz);
+ rc = zone->z_ops->allocate(zone, sz, &alloc_addr);
- if (alloc_addr < 0) {
+ if (rc) {
pr_err("Zone Allocation operation failed\n");
goto internal_error;
}
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 9a5883f..6cd6ffe 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -176,12 +176,25 @@
static int pil_lpass_reset_trusted(struct pil_desc *pil)
{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ int ret;
+
+ ret = clk_prepare_enable(drv->axi_clk);
+ if (ret)
+ return ret;
return pas_auth_and_reset(PAS_Q6);
}
static int pil_lpass_shutdown_trusted(struct pil_desc *pil)
{
- return pas_shutdown(PAS_Q6);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ int ret;
+
+ ret = pas_shutdown(PAS_Q6);
+ if (ret)
+ return ret;
+ clk_disable_unprepare(drv->axi_clk);
+ return 0;
}
static struct pil_reset_ops pil_lpass_ops_trusted = {
@@ -410,12 +423,6 @@
drv->err_fatal_irq = ret;
ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-ready", 0));
- if (ret < 0)
- return ret;
- drv->subsys_desc.err_ready_irq = ret;
-
- ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
"qcom,gpio-proxy-unvote", 0));
if (ret < 0)
return ret;
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 5419bf0..7fd76ab 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -313,6 +313,7 @@
}
pr_err("riva: smsm state changed to smsm reset\n");
+ wcnss_riva_dump_pmic_regs();
smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
&smem_reset_size);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index afb2b84..4a54dd4 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -35,7 +35,10 @@
#include <mach/system.h>
#include <mach/scm.h>
#include <mach/socinfo.h>
+#define CREATE_TRACE_POINTS
+#include <mach/trace_msm_low_power.h>
#include <mach/msm-krait-l2-accessors.h>
+#include <mach/msm_bus.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/pgtable.h>
@@ -55,8 +58,7 @@
#include "timer.h"
#include "pm-boot.h"
#include <mach/event_timer.h>
-#define CREATE_TRACE_POINTS
-#include "trace_msm_low_power.h"
+
#define SCM_L2_RETENTION (0x2)
#define SCM_CMD_TERMINATE_PC (0x2)
@@ -854,8 +856,10 @@
time = ktime_to_ns(ktime_get());
if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ int64_t ns = msm_pm_timer_enter_idle();
notify_rpm = true;
- sleep_delay = (uint32_t)msm_pm_timer_enter_idle();
+ do_div(ns, NSEC_PER_SEC / SCLK_HZ);
+ sleep_delay = (uint32_t)ns;
if (sleep_delay == 0) /* 0 would mean infinite time */
sleep_delay = 1;
@@ -1110,6 +1114,36 @@
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
};
+
+static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
+ static uint32_t msm_pm_bus_client;
+
+ msm_pm_bus_pdata = msm_bus_cl_get_pdata(pdev);
+
+ if (msm_pm_bus_pdata) {
+ msm_pm_bus_client =
+ msm_bus_scale_register_client(msm_pm_bus_pdata);
+
+ if (!msm_pm_bus_client) {
+ pr_err("%s: Failed to register SNOC client",
+ __func__);
+ rc = -ENXIO;
+ goto snoc_cl_probe_done;
+ }
+
+ rc = msm_bus_scale_client_update_request(msm_pm_bus_client, 1);
+
+ if (rc)
+ pr_err("%s: Error setting bus rate", __func__);
+ }
+
+snoc_cl_probe_done:
+ return rc;
+}
+
static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
{
struct msm_pm_sleep_status_data *pdata;
@@ -1198,6 +1232,21 @@
},
};
+static struct of_device_id msm_snoc_clnt_match_tbl[] = {
+ {.compatible = "qcom,pm-snoc-client"},
+ {},
+};
+
+static struct platform_driver msm_cpu_pm_snoc_client_driver = {
+ .probe = msm_pm_snoc_client_probe,
+ .driver = {
+ .name = "pm_snoc_client",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_snoc_clnt_match_tbl,
+ },
+};
+
+
static int __init msm_pm_setup_saved_state(void)
{
pgd_t *pc_pgd;
@@ -1538,6 +1587,14 @@
return rc;
}
+ rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
+
+ if (rc) {
+ pr_err("%s(): failed to register driver %s\n", __func__,
+ msm_cpu_pm_snoc_client_driver.driver.name);
+ return rc;
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 1eb66f4..38ed867 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -36,9 +36,9 @@
#include <mach/socinfo.h>
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
-#include "rpm-notifier.h"
#define CREATE_TRACE_POINTS
-#include "trace_rpm_smd.h"
+#include <mach/trace_rpm_smd.h>
+#include "rpm-notifier.h"
/* Debug Definitions */
enum {
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
index b0cb88f..f3effa8 100644
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ b/arch/arm/mach-msm/sdio_al_dloader.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -228,6 +228,7 @@
static unsigned long lock_flags2;
static atomic_t sdio_dld_in_use = ATOMIC_INIT(0);
+static atomic_t sdio_dld_setup_done = ATOMIC_INIT(0);
/*
* sdio_op_mode sets the operation mode of the sdio_dloader -
@@ -2388,6 +2389,14 @@
if (atomic_read(&sdio_dld_in_use) == 1)
return -EBUSY;
+ /*
+ * If the setup is already complete tear down the existing
+ * one and reinitialize. This might happen during modem restarts
+ * in boot phase.
+ */
+ if (atomic_read(&sdio_dld_setup_done) == 1)
+ sdio_dld_tear_down(NULL);
+
if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) {
pr_err(MODULE_NAME ": %s - invalid number of devices\n",
__func__);
@@ -2478,6 +2487,7 @@
pr_err(MODULE_NAME ": %s - tty_register_device() "
"failed\n", __func__);
tty_unregister_driver(sdio_dld->tty_drv);
+ put_tty_driver(sdio_dld->tty_drv);
kfree(sdio_dld);
return PTR_ERR(tty_dev);
}
@@ -2518,6 +2528,7 @@
goto exit_err;
}
+ atomic_set(&sdio_dld_setup_done, 1);
return 0;
exit_err:
@@ -2526,7 +2537,9 @@
if (result)
pr_err(MODULE_NAME ": %s - tty_unregister_driver() "
"failed. result=%d\n", __func__, -result);
+ put_tty_driver(sdio_dld->tty_drv);
kfree(sdio_dld);
+ atomic_set(&sdio_dld_setup_done, 0);
return status;
}
@@ -2534,22 +2547,24 @@
{
int status = 0;
- del_timer_sync(&sdio_dld->timer);
- del_timer_sync(&sdio_dld->push_timer);
-
- sdio_dld_dealloc_local_buffers();
+ if (atomic_read(&sdio_dld_in_use) == 1) {
+ del_timer_sync(&sdio_dld->timer);
+ del_timer_sync(&sdio_dld->push_timer);
+ sdio_dld_dealloc_local_buffers();
+ }
tty_unregister_device(sdio_dld->tty_drv, 0);
status = tty_unregister_driver(sdio_dld->tty_drv);
-
if (status) {
pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
__func__);
}
+ put_tty_driver(sdio_dld->tty_drv);
kfree(sdio_dld);
atomic_set(&sdio_dld_in_use, 0);
+ atomic_set(&sdio_dld_setup_done, 0);
}
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 1945651..a177593 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3939,12 +3939,11 @@
}
registered = true;
- rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+ rc = init_smem_remote_spinlock();
if (rc) {
pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
return rc;
}
- spinlocks_initialized = 1;
rc = platform_driver_register(&msm_smd_driver);
if (rc) {
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4fe9592..2096063 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -155,27 +155,6 @@
struct smd_half_channel_access *get_half_ch_funcs(unsigned ch_type);
-struct smem_ram_ptn {
- char name[16];
- unsigned start;
- unsigned size;
-
- /* RAM Partition attribute: READ_ONLY, READWRITE etc. */
- unsigned attr;
-
- /* RAM Partition category: EBI0, EBI1, IRAM, IMEM */
- unsigned category;
-
- /* RAM Partition domain: APPS, MODEM, APPS & MODEM (SHARED) etc. */
- unsigned domain;
-
- /* RAM Partition type: system, bootloader, appsboot, apps etc. */
- unsigned type;
-
- /* reserved for future expansion without changing version number */
- unsigned reserved2, reserved3, reserved4, reserved5;
-} __attribute__ ((__packed__));
-
struct smd_channel {
volatile void __iomem *send; /* some variant of smd_half_channel */
volatile void __iomem *recv; /* some variant of smd_half_channel */
@@ -217,54 +196,6 @@
struct smd_half_channel_access *half_ch;
};
-struct smem_ram_ptable {
- #define _SMEM_RAM_PTABLE_MAGIC_1 0x9DA5E0A8
- #define _SMEM_RAM_PTABLE_MAGIC_2 0xAF9EC4E2
- unsigned magic[2];
- unsigned version;
- unsigned reserved1;
- unsigned len;
- struct smem_ram_ptn parts[32];
- unsigned buf;
-} __attribute__ ((__packed__));
-
-/* SMEM RAM Partition */
-enum {
- DEFAULT_ATTRB = ~0x0,
- READ_ONLY = 0x0,
- READWRITE,
-};
-
-enum {
- DEFAULT_CATEGORY = ~0x0,
- SMI = 0x0,
- EBI1,
- EBI2,
- QDSP6,
- IRAM,
- IMEM,
- EBI0_CS0,
- EBI0_CS1,
- EBI1_CS0,
- EBI1_CS1,
- SDRAM = 0xE,
-};
-
-enum {
- DEFAULT_DOMAIN = 0x0,
- APPS_DOMAIN,
- MODEM_DOMAIN,
- SHARED_DOMAIN,
-};
-
-enum {
- SYS_MEMORY = 1, /* system memory*/
- BOOT_REGION_MEMORY1, /* boot loader memory 1*/
- BOOT_REGION_MEMORY2, /* boot loader memory 2,reserved*/
- APPSBL_MEMORY, /* apps boot loader memory*/
- APPS_MEMORY, /* apps usage memory*/
-};
-
extern spinlock_t smem_lock;
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index c00f96f..2204609 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -56,6 +56,7 @@
struct ramdump_segment *smem_ramdump_segments;
static void *smem_ramdump_dev;
+static DEFINE_MUTEX(spinlock_init_lock);
struct restart_notifier_block {
unsigned processor;
@@ -215,6 +216,7 @@
struct smem_heap_entry *toc = shared->heap_toc;
unsigned long flags;
void *ret = NULL;
+ int rc;
if (!shared->heap_info.initialized) {
pr_err("%s: smem heap info not initialized\n", __func__);
@@ -224,6 +226,15 @@
if (id >= SMEM_NUM_ITEMS)
return NULL;
+ if (unlikely(!spinlocks_initialized)) {
+ rc = init_smem_remote_spinlock();
+ if (unlikely(rc)) {
+ pr_err("%s: remote spinlock init failed %d\n",
+ __func__, rc);
+ return NULL;
+ }
+ }
+
size_in = ALIGN(size_in, 8);
remote_spin_lock_irqsave(&remote_spinlock, flags);
if (toc[id].allocated) {
@@ -301,6 +312,35 @@
}
EXPORT_SYMBOL(smem_get_remote_spinlock);
+/**
+ * init_smem_remote_spinlock - Reentrant remote spinlock initialization
+ *
+ * @returns: sucess or error code for failure
+ */
+int init_smem_remote_spinlock(void)
+{
+ int rc = 0;
+
+ /*
+ * Optimistic locking. Init only needs to be done once by the first
+ * caller. After that, serializing inits between different callers
+ * is unnecessary. The second check after the lock ensures init
+ * wasn't previously completed by someone else before the lock could
+ * be grabbed.
+ */
+ if (!spinlocks_initialized) {
+ mutex_lock(&spinlock_init_lock);
+ if (!spinlocks_initialized) {
+ rc = remote_spin_lock_init(&remote_spinlock,
+ SMEM_SPINLOCK_SMEM_ALLOC);
+ if (!rc)
+ spinlocks_initialized = 1;
+ }
+ mutex_unlock(&spinlock_init_lock);
+ }
+ return rc;
+}
+
static int restart_notifier_cb(struct notifier_block *this,
unsigned long code,
void *data)
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index 89b2b7b..b631e7c 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -19,7 +19,7 @@
#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
extern remote_spinlock_t remote_spinlock;
-extern int spinlocks_initialized;
+extern int spinlocks_initialized; /* only modify in init_smem_remote_spinlock */
#define SMD_HEAP_SIZE 512
@@ -65,4 +65,10 @@
/* used for unit testing spinlocks */
remote_spinlock_t *smem_get_remote_spinlock(void);
+
+/*
+ * used to ensure the remote spinlock is only inited once since local
+ * spinlock init code appears non-reentrant
+ */
+int init_smem_remote_spinlock(void);
#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 0c02b51..575cb49 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -324,6 +324,12 @@
/* 8226 IDs */
[145] = MSM_CPU_8226,
+ [158] = MSM_CPU_8226,
+ [159] = MSM_CPU_8226,
+ [198] = MSM_CPU_8226,
+ [199] = MSM_CPU_8226,
+ [200] = MSM_CPU_8226,
+ [205] = MSM_CPU_8226,
/* 8092 IDs */
[146] = MSM_CPU_8092,
@@ -364,6 +370,9 @@
/* FSM9900 ID */
[188] = FSM_CPU_9900,
+ /* Samarium IDs */
+ [195] = MSM_CPU_SAMARIUM,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -871,6 +880,10 @@
dummy_socinfo.id = 187;
strlcpy(dummy_socinfo.build_id, "msmkrypton - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_msmsamarium()) {
+ dummy_socinfo.id = 195;
+ strlcpy(dummy_socinfo.build_id, "msmsamarium - ",
+ sizeof(dummy_socinfo.build_id));
}
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
sizeof(dummy_socinfo.build_id));
diff --git a/arch/arm/mach-msm/spm-regulator.c b/arch/arm/mach-msm/spm-regulator.c
index 00817c0..244a779 100644
--- a/arch/arm/mach-msm/spm-regulator.c
+++ b/arch/arm/mach-msm/spm-regulator.c
@@ -42,17 +42,40 @@
static const struct voltage_range fts2_range0 = {0, 350000, 1275000, 5000};
static const struct voltage_range fts2_range1 = {0, 700000, 2040000, 10000};
-/* Specifies the PMIC internal slew rate in uV/us. */
-#define QPNP_FTS2_SLEW_RATE 6000
-
#define QPNP_FTS2_REG_TYPE 0x04
#define QPNP_FTS2_REG_SUBTYPE 0x05
#define QPNP_FTS2_REG_VOLTAGE_RANGE 0x40
#define QPNP_FTS2_REG_VOLTAGE_SETPOINT 0x41
+#define QPNP_FTS2_REG_MODE 0x45
+#define QPNP_FTS2_REG_STEP_CTRL 0x61
#define QPNP_FTS2_TYPE 0x1C
#define QPNP_FTS2_SUBTYPE 0x08
+#define QPNP_FTS2_MODE_PWM 0x80
+#define QPNP_FTS2_MODE_AUTO 0x40
+
+#define QPNP_FTS2_STEP_CTRL_STEP_MASK 0x18
+#define QPNP_FTS2_STEP_CTRL_STEP_SHIFT 3
+#define QPNP_FTS2_STEP_CTRL_DELAY_MASK 0x07
+#define QPNP_FTS2_STEP_CTRL_DELAY_SHIFT 0
+
+/* Clock rate in kHz of the FTS2 regulator reference clock. */
+#define QPNP_FTS2_CLOCK_RATE 19200
+
+/* 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
+
+/*
+ * 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
+
struct spm_vreg {
struct regulator_desc rdesc;
struct regulator_dev *rdev;
@@ -64,8 +87,23 @@
unsigned last_set_vlevel;
bool online;
u16 spmi_base_addr;
+ u8 init_mode;
+ int step_rate;
};
+static int qpnp_fts2_set_mode(struct spm_vreg *vreg, u8 mode)
+{
+ int rc;
+
+ rc = spmi_ext_register_writel(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
+ vreg->spmi_base_addr + QPNP_FTS2_REG_MODE, &mode, 1);
+ if (rc)
+ dev_err(&vreg->spmi_dev->dev, "%s: could not write to mode register, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
{
struct spm_vreg *vreg = rdev_get_drvdata(rdev);
@@ -74,6 +112,14 @@
if (vreg->vlevel == vreg->last_set_vlevel)
return 0;
+ if (!(vreg->init_mode & QPNP_FTS2_MODE_PWM)
+ && vreg->uV > vreg->last_set_uV) {
+ /* Switch to PWM mode so that voltage ramping is fast. */
+ rc = qpnp_fts2_set_mode(vreg, QPNP_FTS2_MODE_PWM);
+ if (rc)
+ return rc;
+ }
+
rc = msm_spm_apcs_set_vdd(vreg->vlevel);
if (rc) {
pr_err("%s: msm_spm_set_vdd failed %d\n", vreg->rdesc.name, rc);
@@ -81,10 +127,21 @@
}
if (vreg->uV > vreg->last_set_uV) {
- /* Wait for voltage to stabalize. */
+ /* Wait for voltage stepping to complete. */
udelay(DIV_ROUND_UP(vreg->uV - vreg->last_set_uV,
- QPNP_FTS2_SLEW_RATE));
+ vreg->step_rate));
}
+
+ if (!(vreg->init_mode & QPNP_FTS2_MODE_PWM)
+ && vreg->uV > vreg->last_set_uV) {
+ /* 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_fts2_set_mode(vreg, QPNP_FTS2_MODE_AUTO);
+ if (rc)
+ return rc;
+ }
+
vreg->last_set_uV = vreg->uV;
vreg->last_set_vlevel = vreg->vlevel;
@@ -254,6 +311,51 @@
return rc;
}
+static int qpnp_fts2_init_mode(struct spm_vreg *vreg)
+{
+ int rc;
+
+ rc = spmi_ext_register_readl(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
+ vreg->spmi_base_addr + QPNP_FTS2_REG_MODE, &vreg->init_mode, 1);
+ if (rc)
+ dev_err(&vreg->spmi_dev->dev, "%s: could not read mode register, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int qpnp_fts2_init_step_rate(struct spm_vreg *vreg)
+{
+ int rc;
+ u8 reg = 0;
+ int step, delay;
+
+ rc = spmi_ext_register_readl(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
+ vreg->spmi_base_addr + QPNP_FTS2_REG_STEP_CTRL, ®, 1);
+ if (rc) {
+ dev_err(&vreg->spmi_dev->dev, "%s: could not read stepping control register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ step = (reg & QPNP_FTS2_STEP_CTRL_STEP_MASK)
+ >> QPNP_FTS2_STEP_CTRL_STEP_SHIFT;
+ delay = (reg & QPNP_FTS2_STEP_CTRL_DELAY_MASK)
+ >> QPNP_FTS2_STEP_CTRL_DELAY_SHIFT;
+
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_FTS2_CLOCK_RATE * vreg->range->step_uV
+ * (1 << step);
+ vreg->step_rate /= 1000 * (8 << delay);
+ 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 __devinit spm_regulator_probe(struct spmi_device *spmi)
{
struct device_node *node = spmi->dev.of_node;
@@ -299,6 +401,14 @@
if (rc)
return rc;
+ rc = qpnp_fts2_init_mode(vreg);
+ if (rc)
+ return rc;
+
+ rc = qpnp_fts2_init_step_rate(vreg);
+ if (rc)
+ return rc;
+
init_data = of_get_regulator_init_data(&spmi->dev, node);
if (!init_data) {
dev_err(&spmi->dev, "%s: unable to allocate memory\n",
@@ -334,8 +444,12 @@
dev_set_drvdata(&spmi->dev, vreg);
- pr_info("name=%s, range=%d\n", vreg->rdesc.name,
- (vreg->range == &fts2_range0) ? 0 : 1);
+ pr_info("name=%s, range=%s, voltage=%d uV, mode=%s, step rate=%d uV/us\n",
+ vreg->rdesc.name, vreg->range == &fts2_range0 ? "LV" : "MV",
+ vreg->uV,
+ vreg->init_mode & QPNP_FTS2_MODE_PWM ? "PWM" :
+ (vreg->init_mode & QPNP_FTS2_MODE_AUTO ? "AUTO" : "PFM"),
+ vreg->step_rate);
return rc;
}
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index c971896..b956649 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -41,6 +41,9 @@
#include "smd_private.h"
+static int enable_debug;
+module_param(enable_debug, int, S_IRUGO | S_IWUSR);
+
/**
* enum p_subsys_state - state of a subsystem (private)
* @SUBSYS_NORMAL: subsystem is operating normally
@@ -419,7 +422,7 @@
{
int ret;
- if (!subsys->desc->err_ready_irq)
+ if (!subsys->desc->err_ready_irq || enable_debug == 1)
return 0;
ret = wait_for_completion_timeout(&subsys->err_ready,
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 26b92d4..34cb153 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -395,32 +395,29 @@
unsigned long hole_end_virt;
/*
- * Find the start and end of the hole, using meminfo
- * if it hasnt been found already.
+ * Find the start and end of the hole, using meminfo.
*/
- if (memory_hole_start == 0 && memory_hole_end == 0) {
- for (i = 0; i < (meminfo.nr_banks - 1); i++) {
- if ((meminfo.bank[i].start + meminfo.bank[i].size) !=
+ for (i = 0; i < (meminfo.nr_banks - 1); i++) {
+ if ((meminfo.bank[i].start + meminfo.bank[i].size) !=
meminfo.bank[i+1].start) {
- if (meminfo.bank[i].start + meminfo.bank[i].size
+ if (meminfo.bank[i].start + meminfo.bank[i].size
<= MAX_HOLE_ADDRESS) {
- hole_start = meminfo.bank[i].start +
+ hole_start = meminfo.bank[i].start +
meminfo.bank[i].size;
- hole_size = meminfo.bank[i+1].start -
+ hole_size = meminfo.bank[i+1].start -
hole_start;
- if (memory_hole_start == 0 &&
+ if (memory_hole_start == 0 &&
memory_hole_end == 0) {
- memory_hole_start = hole_start;
- memory_hole_end = hole_start +
+ memory_hole_start = hole_start;
+ memory_hole_end = hole_start +
hole_size;
- } else if ((memory_hole_end -
+ } else if ((memory_hole_end -
memory_hole_start) <= hole_size) {
- memory_hole_start = hole_start;
- memory_hole_end = hole_start +
+ memory_hole_start = hole_start;
+ memory_hole_end = hole_start +
hole_size;
- }
}
}
}
diff --git a/block/blk-core.c b/block/blk-core.c
index 2b6595c..153240e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1086,7 +1086,7 @@
* urgent requests. We want to be able to track this
* down.
*/
- pr_err("%s(): requeueing an URGENT request", __func__);
+ pr_debug("%s(): requeueing an URGENT request", __func__);
WARN_ON(!q->dispatched_urgent);
q->dispatched_urgent = false;
}
@@ -1123,7 +1123,7 @@
* urgent requests. We want to be able to track this
* down.
*/
- pr_err("%s(): reinserting an URGENT request", __func__);
+ pr_debug("%s(): reinserting an URGENT request", __func__);
WARN_ON(!q->dispatched_urgent);
q->dispatched_urgent = false;
}
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 51578e0..e98fff2 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -26,10 +26,13 @@
#include <linux/msm_ion.h>
#include <mach/msm_smd.h>
#include <mach/ion.h>
+#include <mach/iommu_domains.h>
#include <linux/scatterlist.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/iommu.h>
#ifndef ION_ADSPRPC_HEAP_ID
#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
@@ -53,6 +56,8 @@
} while (0)
+#define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
+
static inline uint32_t buf_page_start(void *buf)
{
uint32_t start = (uint32_t) buf & PAGE_MASK;
@@ -84,8 +89,9 @@
{
struct vm_area_struct *vma;
uint32_t start = buf_page_start(addr);
+ uint32_t end = buf_page_start((void *)((uint32_t)addr + sz - 1));
uint32_t len = nr_pages << PAGE_SHIFT;
- unsigned long pfn;
+ unsigned long pfn, pfnend;
int n = -1, err = 0;
VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
@@ -102,6 +108,12 @@
VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
if (err)
goto bail;
+ VERIFY(err, 0 == follow_pfn(vma, end, &pfnend));
+ if (err)
+ goto bail;
+ VERIFY(err, (pfn + nr_pages - 1) == pfnend);
+ if (err)
+ goto bail;
VERIFY(err, nr_elems > 0);
if (err)
goto bail;
@@ -124,6 +136,13 @@
int last;
};
+struct fastrpc_smmu {
+ struct iommu_group *group;
+ struct iommu_domain *domain;
+ int domain_id;
+ bool enabled;
+};
+
struct fastrpc_apps {
smd_channel_t *chan;
struct smq_context_list clst;
@@ -132,6 +151,7 @@
struct cdev cdev;
struct class *class;
struct device *dev;
+ struct fastrpc_smmu smmu;
dev_t dev_no;
spinlock_t wrlock;
spinlock_t hlock;
@@ -172,7 +192,12 @@
{
struct fastrpc_apps *me = &gfa;
- if (buf->handle) {
+ if (!IS_ERR_OR_NULL(buf->handle)) {
+ if (me->smmu.enabled && buf->phys) {
+ ion_unmap_iommu(me->iclient, buf->handle,
+ me->smmu.domain_id, 0);
+ buf->phys = 0;
+ }
if (buf->virt) {
ion_unmap_kernel(me->iclient, buf->handle);
buf->virt = 0;
@@ -185,7 +210,7 @@
static void free_map(struct fastrpc_mmap *map)
{
struct fastrpc_apps *me = &gfa;
- if (map->handle) {
+ if (!IS_ERR_OR_NULL(map->handle)) {
if (map->virt) {
ion_unmap_kernel(me->iclient, map->handle);
map->virt = 0;
@@ -197,26 +222,39 @@
static int alloc_mem(struct fastrpc_buf *buf)
{
+ struct fastrpc_apps *me = &gfa;
struct ion_client *clnt = gfa.iclient;
struct sg_table *sg;
int err = 0;
+ unsigned int heap;
+ unsigned long len;
buf->handle = 0;
buf->virt = 0;
- buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ heap = me->smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
+ ION_HEAP(ION_ADSP_HEAP_ID) | ION_HEAP(ION_AUDIO_HEAP_ID);
+ buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, 0);
VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
if (err)
goto bail;
VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
if (err)
goto bail;
- VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
- if (err)
- goto bail;
- VERIFY(err, 1 == sg->nents);
- if (err)
- goto bail;
- buf->phys = sg_dma_address(sg->sgl);
+ if (me->smmu.enabled) {
+ len = buf->size;
+ VERIFY(err, 0 == ion_map_iommu(clnt, buf->handle,
+ me->smmu.domain_id, 0, SZ_4K, 0,
+ &buf->phys, &len, 0, 0));
+ if (err)
+ goto bail;
+ } else {
+ VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
+ if (err)
+ goto bail;
+ VERIFY(err, 1 == sg->nents);
+ if (err)
+ goto bail;
+ buf->phys = sg_dma_address(sg->sgl);
+ }
bail:
if (err && !IS_ERR_OR_NULL(buf->handle))
free_mem(buf);
@@ -481,6 +519,28 @@
return err;
}
+static void inv_args_pre(uint32_t sc, remote_arg_t *rpra)
+{
+ int i, inbufs, outbufs;
+ uint32_t end;
+
+ inbufs = REMOTE_SCALARS_INBUFS(sc);
+ outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+ for (i = inbufs; i < inbufs + outbufs; ++i) {
+ if (!rpra[i].buf.len)
+ continue;
+ if (buf_page_start(rpra) == buf_page_start(rpra[i].buf.pv))
+ continue;
+ if (!IS_CACHE_ALIGNED((uint32_t)rpra[i].buf.pv))
+ dmac_flush_range(rpra[i].buf.pv,
+ (char *)rpra[i].buf.pv + 1);
+ end = (uint32_t)rpra[i].buf.pv + rpra[i].buf.len;
+ if (!IS_CACHE_ALIGNED(end))
+ dmac_flush_range((char *)end,
+ (char *)end + 1);
+ }
+}
+
static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
{
int i, inbufs, outbufs;
@@ -572,6 +632,8 @@
{
int err = 0;
struct fastrpc_apps *me = &gfa;
+ struct device_node *node;
+ bool enabled = 0;
if (me->chan == 0) {
int i;
@@ -588,6 +650,22 @@
VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
if (err)
goto ion_bail;
+ node = of_find_compatible_node(NULL, NULL,
+ "qcom,msm-audio-ion");
+ if (node)
+ enabled = of_property_read_bool(node,
+ "qcom,smmu-enabled");
+ if (enabled)
+ me->smmu.group = iommu_group_find("lpass_audio");
+ if (me->smmu.group)
+ me->smmu.domain = iommu_group_get_iommudata(
+ me->smmu.group);
+ if (!IS_ERR_OR_NULL(me->smmu.domain)) {
+ me->smmu.domain_id = msm_find_domain_no(
+ me->smmu.domain);
+ if (me->smmu.domain_id >= 0)
+ me->smmu.enabled = enabled;
+ }
VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
SMD_APPS_QDSP, &me->chan,
me, smd_event_handler));
@@ -704,6 +782,12 @@
sc = invoke->sc;
obuf.handle = 0;
+ if (me->smmu.enabled) {
+ VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
+ me->smmu.group));
+ if (err)
+ return err;
+ }
if (REMOTE_SCALARS_LENGTH(sc)) {
VERIFY(err, 0 == get_dev(me, &dev));
if (err)
@@ -720,6 +804,7 @@
}
context_list_alloc_ctx(&me->clst, &ctx);
+ inv_args_pre(sc, rpra);
VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
ctx, &obuf));
if (err)
@@ -743,6 +828,8 @@
}
context_free(ctx);
+ if (me->smmu.enabled)
+ iommu_detach_group(me->smmu.domain, me->smmu.group);
for (i = 0, b = abufs; i < nbufs; ++i, ++b)
free_mem(b);
@@ -1093,6 +1180,7 @@
struct fastrpc_apps *me = &gfa;
int err = 0;
+ memset(me, 0, sizeof(*me));
VERIFY(err, 0 == fastrpc_init());
if (err)
goto fastrpc_bail;
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 684f11d..292a0be 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -219,6 +219,7 @@
int num_clients;
int polling_reg_flag;
struct diag_write_device *buf_tbl;
+ unsigned int buf_tbl_size;
int use_device_tree;
/* DCI related variables */
struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 7022a6f..96e8b11 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1167,7 +1167,7 @@
/* place holder for number of data field */
ret += 4;
- for (i = 0; i < driver->poolsize_write_struct; i++) {
+ for (i = 0; i < driver->buf_tbl_size; i++) {
if (driver->buf_tbl[i].length > 0) {
#ifdef DIAG_DEBUG
pr_debug("diag: WRITING the buf address "
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 151e304..9c2c8b1 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -48,7 +48,8 @@
int diag_debug_buf_idx;
unsigned char diag_debug_buf[1024];
-static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
+/* Number of entries in table of buffers */
+static unsigned int buf_tbl_size = 10;
struct diag_master_table entry;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
@@ -467,7 +468,7 @@
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
int hsic_updated = 0;
if (data_type == APPS_DATA) {
- for (i = 0; i < driver->poolsize_write_struct; i++)
+ for (i = 0; i < driver->buf_tbl_size; i++)
if (driver->buf_tbl[i].length == 0) {
driver->buf_tbl[i].buf = buf;
driver->buf_tbl[i].length =
@@ -688,9 +689,15 @@
int len, int type)
{
driver->pkt_length = len;
- if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
- diag_update_pkt_buffer(buf);
- diag_update_sleeping_process(entry.process_id, PKT_TYPE);
+
+ /* If the process_id corresponds to an apps process */
+ if (entry.process_id != NON_APPS_PROC) {
+ /* If the message is to be sent to the apps process */
+ if (type != MODEM_DATA) {
+ diag_update_pkt_buffer(buf);
+ diag_update_sleeping_process(entry.process_id,
+ PKT_TYPE);
+ }
} else {
if (len > 0) {
if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
@@ -1768,6 +1775,12 @@
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
driver->real_time_mode = 1;
+ /*
+ * The number of entries in table of buffers
+ * should not be any smaller than hdlc poolsize.
+ */
+ driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
+ driver->poolsize_hdlc : buf_tbl_size;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
@@ -1802,7 +1815,7 @@
goto err;
kmemleak_not_leak(driver->client_map);
if (driver->buf_tbl == NULL)
- driver->buf_tbl = kzalloc(buf_tbl_size *
+ driver->buf_tbl = kzalloc(driver->buf_tbl_size *
sizeof(struct diag_write_device), GFP_KERNEL);
if (driver->buf_tbl == NULL)
goto err;
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0e2e2d9..2b14f86 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -2,7 +2,6 @@
# Makefile for CoreSight drivers.
#
obj-$(CONFIG_CORESIGHT) += coresight.o
-obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 235a340..85c28d4 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -80,6 +80,8 @@
*/
static DEFINE_MUTEX(dbs_mutex);
+static struct workqueue_struct *dbs_wq;
+
static struct dbs_tuners {
unsigned int sampling_rate;
unsigned int sampling_down_factor;
@@ -455,7 +457,7 @@
dbs_check_cpu(dbs_info);
- schedule_delayed_work_on(cpu, &dbs_info->work, delay);
+ queue_delayed_work_on(cpu, dbs_wq, &dbs_info->work, delay);
mutex_unlock(&dbs_info->timer_mutex);
}
@@ -467,7 +469,7 @@
dbs_info->enable = 1;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
- schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
+ queue_delayed_work_on(dbs_info->cpu, dbs_wq, &dbs_info->work, delay);
}
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -602,12 +604,19 @@
static int __init cpufreq_gov_dbs_init(void)
{
+ dbs_wq = alloc_workqueue("conservative_dbs_wq", WQ_HIGHPRI, 0);
+ if (!dbs_wq) {
+ printk(KERN_ERR "Failed to create conservative_dbs_wq workqueue\n");
+ return -EFAULT;
+ }
+
return cpufreq_register_governor(&cpufreq_gov_conservative);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_conservative);
+ destroy_workqueue(dbs_wq);
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index a506aa8..79f7174 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -4,6 +4,7 @@
* Copyright (C) 2001 Russell King
* (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* Jun Nakajima <jun.nakajima@intel.com>
+ * (c) 2013 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 as
@@ -115,7 +116,7 @@
*/
static DEFINE_MUTEX(dbs_mutex);
-static struct workqueue_struct *input_wq;
+static struct workqueue_struct *dbs_wq;
struct dbs_work_struct {
struct work_struct work;
@@ -124,6 +125,14 @@
static DEFINE_PER_CPU(struct dbs_work_struct, dbs_refresh_work);
+struct dbs_sync_work_struct {
+ struct work_struct work;
+ unsigned int src_cpu;
+ unsigned int targ_cpu;
+};
+
+static DEFINE_PER_CPU(struct dbs_sync_work_struct, dbs_sync_work);
+
static struct dbs_tuners {
unsigned int sampling_rate;
unsigned int up_threshold;
@@ -367,8 +376,8 @@
cancel_delayed_work_sync(&dbs_info->work);
mutex_lock(&dbs_info->timer_mutex);
- schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work,
- usecs_to_jiffies(new_rate));
+ queue_delayed_work_on(dbs_info->cpu, dbs_wq,
+ &dbs_info->work, usecs_to_jiffies(new_rate));
}
mutex_unlock(&dbs_info->timer_mutex);
@@ -932,7 +941,7 @@
dbs_info->freq_lo, CPUFREQ_RELATION_H);
delay = dbs_info->freq_lo_jiffies;
}
- schedule_delayed_work_on(cpu, &dbs_info->work, delay);
+ queue_delayed_work_on(cpu, dbs_wq, &dbs_info->work, delay);
mutex_unlock(&dbs_info->timer_mutex);
}
@@ -946,7 +955,7 @@
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
- schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
+ queue_delayed_work_on(dbs_info->cpu, dbs_wq, &dbs_info->work, delay);
}
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -1020,6 +1029,92 @@
return;
}
+static int dbs_migration_notify(struct notifier_block *nb,
+ unsigned long target_cpu, void *arg)
+{
+ struct dbs_sync_work_struct *sync_work =
+ &per_cpu(dbs_sync_work, target_cpu);
+ sync_work->src_cpu = (unsigned int)arg;
+
+ queue_work_on(target_cpu, dbs_wq,
+ &per_cpu(dbs_sync_work, target_cpu).work);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block dbs_migration_nb = {
+ .notifier_call = dbs_migration_notify,
+};
+
+void dbs_synchronize(struct work_struct *work)
+{
+ struct cpufreq_policy *policy;
+ struct cpu_dbs_info_s *this_dbs_info, *src_dbs_info;
+ struct dbs_sync_work_struct *dbs_work;
+ unsigned int cpu, src_cpu;
+ unsigned int src_freq, src_max_load;
+ int delay;
+
+ dbs_work = container_of(work, struct dbs_sync_work_struct, work);
+ cpu = dbs_work->targ_cpu;
+ src_cpu = dbs_work->src_cpu;
+
+ get_online_cpus();
+
+ /* Getting source cpu info */
+ src_dbs_info = &per_cpu(od_cpu_dbs_info, src_cpu);
+ if (src_dbs_info != NULL && src_dbs_info->cur_policy != NULL) {
+ src_freq = src_dbs_info->cur_policy->cur;
+ src_max_load = src_dbs_info->max_load;
+ } else {
+ src_freq = dbs_tuners_ins.sync_freq;
+ src_max_load = 0;
+ }
+
+ if (lock_policy_rwsem_write(cpu) < 0)
+ goto bail_acq_sema_failed;
+
+ this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
+ policy = this_dbs_info->cur_policy;
+ if (!policy) {
+ /* CPU not using ondemand governor */
+ goto bail_incorrect_governor;
+ }
+
+ delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+ if (policy->cur < src_freq) {
+
+ /* Cancelling the next ondemand sample */
+ cancel_delayed_work_sync(&this_dbs_info->work);
+
+ /*
+ * Arch specific cpufreq driver may fail.
+ * Don't update governor frequency upon failure.
+ */
+ if (__cpufreq_driver_target(policy, src_freq,
+ CPUFREQ_RELATION_L) >= 0) {
+ policy->cur = src_freq;
+ if (src_max_load > this_dbs_info->max_load) {
+ this_dbs_info->max_load = src_max_load;
+ this_dbs_info->prev_load = src_max_load;
+ }
+ }
+
+ /* Rescheduling the next ondemand sample */
+ mutex_lock(&this_dbs_info->timer_mutex);
+ schedule_delayed_work_on(cpu, &this_dbs_info->work,
+ delay);
+ mutex_unlock(&this_dbs_info->timer_mutex);
+ }
+bail_incorrect_governor:
+ unlock_policy_rwsem_write(cpu);
+
+bail_acq_sema_failed:
+ put_online_cpus();
+ return;
+}
+
static void dbs_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
@@ -1032,7 +1127,7 @@
}
for_each_online_cpu(i)
- queue_work_on(i, input_wq, &per_cpu(dbs_refresh_work, i).work);
+ queue_work_on(i, dbs_wq, &per_cpu(dbs_refresh_work, i).work);
}
static int dbs_input_connect(struct input_handler *handler,
@@ -1148,6 +1243,9 @@
if (dbs_tuners_ins.sync_freq == 0)
dbs_tuners_ins.sync_freq = policy->min;
+
+ atomic_notifier_chain_register(&migration_notifier_head,
+ &dbs_migration_nb);
}
if (!cpu)
rc = input_register_handler(&dbs_input_handler);
@@ -1171,9 +1269,14 @@
this_dbs_info->cur_policy = NULL;
if (!cpu)
input_unregister_handler(&dbs_input_handler);
- if (!dbs_enable)
+ if (!dbs_enable) {
sysfs_remove_group(cpufreq_global_kobject,
&dbs_attr_group);
+ atomic_notifier_chain_unregister(
+ &migration_notifier_head,
+ &dbs_migration_nb);
+ }
+
mutex_unlock(&dbs_mutex);
break;
@@ -1222,9 +1325,9 @@
MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10);
}
- input_wq = create_workqueue("iewq");
- if (!input_wq) {
- printk(KERN_ERR "Failed to create iewq workqueue\n");
+ dbs_wq = alloc_workqueue("ondemand_dbs_wq", WQ_HIGHPRI, 0);
+ if (!dbs_wq) {
+ printk(KERN_ERR "Failed to create ondemand_dbs_wq workqueue\n");
return -EFAULT;
}
for_each_possible_cpu(i) {
@@ -1232,10 +1335,17 @@
&per_cpu(od_cpu_dbs_info, i);
struct dbs_work_struct *dbs_work =
&per_cpu(dbs_refresh_work, i);
+ struct dbs_sync_work_struct *dbs_sync =
+ &per_cpu(dbs_sync_work, i);
mutex_init(&this_dbs_info->timer_mutex);
INIT_WORK(&dbs_work->work, dbs_refresh_callback);
dbs_work->cpu = i;
+
+ INIT_WORK(&dbs_sync->work, dbs_synchronize);
+ dbs_sync->src_cpu = 0;
+ dbs_sync->targ_cpu = i;
+
}
return cpufreq_register_governor(&cpufreq_gov_ondemand);
@@ -1251,7 +1361,7 @@
&per_cpu(od_cpu_dbs_info, i);
mutex_destroy(&this_dbs_info->timer_mutex);
}
- destroy_workqueue(input_wq);
+ destroy_workqueue(dbs_wq);
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 99ace44..3422f05 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -306,7 +306,7 @@
config CRYPTO_DEV_QCE
tristate "Qualcomm Crypto Engine (QCE) module"
select CRYPTO_DEV_QCE40 if ARCH_MSM8960 || ARCH_MSM9615
- select CRYPTO_DEV_QCE50 if ARCH_MSM8974 || ARCH_MSM9625 || ARCH_MSM8226
+ select CRYPTO_DEV_QCE50 if ARCH_MSM8974 || ARCH_MSM9625 || ARCH_MSM8226 || ARCH_MSM8610
default n
help
This driver supports Qualcomm Crypto Engine in MSM7x30, MSM8660
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index 51a74b6..cf75e93 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -32,6 +32,8 @@
#define SHA256_DIGESTSIZE 32
#define SHA1_DIGESTSIZE 20
+#define AES_CE_BLOCK_SIZE 16
+
/* key size in bytes */
#define HMAC_KEY_SIZE (SHA1_DIGESTSIZE) /* hmac-sha1 */
#define SHA_HMAC_KEY_SIZE 64
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 58fa5c9..a3a662a 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -717,6 +717,9 @@
bool sha1 = false;
uint32_t auth_cfg = 0;
+ /* clear status */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/*
@@ -896,6 +899,9 @@
uint32_t ivsize = creq->ivsize;
int i;
+ /* clear status */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/*
@@ -1213,6 +1219,7 @@
{
struct aead_request *areq;
unsigned char mac[SHA256_DIGEST_SIZE];
+ uint32_t status;
areq = (struct aead_request *) pce_dev->areq;
if (areq->src != areq->dst) {
@@ -1227,16 +1234,55 @@
/* check MAC */
memcpy(mac, (char *)(&pce_dev->ce_sps.result->auth_iv[0]),
SHA256_DIGEST_SIZE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
if (pce_dev->mode == QCE_MODE_CCM) {
- uint32_t result_status;
+ int32_t result_status;
+
+ /*
+ * Don't use result dump status. The operation may not
+ * be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+
result_status = pce_dev->ce_sps.result->status;
- result_status &= (1 << CRYPTO_MAC_FAILED);
- result_status |= (pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ pce_dev->ce_sps.result->status = 0;
+
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+
+ pr_err("aead operation error. Status %x\n",
+ status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status |
+ pce_dev->ce_sps.producer_status) {
+ pr_err("aead sps operation error. sps status %x %x\n",
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("aead operation not done? Status %x, sps status %x %x\n",
+ status,
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+
+ } else if (status & (1 << CRYPTO_MAC_FAILED)) {
+ result_status = -EBADMSG;
+ } else {
+ result_status = 0;
+ }
+
pce_dev->qce_cb(areq, mac, NULL, result_status);
+
} else {
uint32_t ivsize = 0;
struct crypto_aead *aead;
@@ -1260,6 +1306,8 @@
struct ahash_request *areq;
unsigned char digest[SHA256_DIGEST_SIZE];
uint32_t bytecount32[2];
+ int32_t result_status = pce_dev->ce_sps.result->status;
+ uint32_t status;
areq = (struct ahash_request *) pce_dev->areq;
qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
@@ -1269,10 +1317,39 @@
_byte_stream_to_net_words(bytecount32,
(unsigned char *)pce_dev->ce_sps.result->auth_byte_count,
2 * CRYPTO_REG_SIZE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
+
+ /*
+ * Don't use result dump status. The operation may not be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+
+ pr_err("sha operation error. Status %x\n", status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status) {
+ pr_err("sha sps operation error. sps status %x\n",
+ pce_dev->ce_sps.consumer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("sha operation not done? Status %x, sps status %x\n",
+ status, pce_dev->ce_sps.consumer_status);
+ result_status = -ENXIO;
+ } else {
+ result_status = 0;
+ }
pce_dev->qce_cb(areq, digest, (char *)bytecount32,
- pce_dev->ce_sps.consumer_status);
+ result_status);
return 0;
};
@@ -1280,6 +1357,8 @@
{
struct ablkcipher_request *areq;
unsigned char iv[NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE];
+ uint32_t status;
+ int32_t result_status;
areq = (struct ablkcipher_request *) pce_dev->areq;
@@ -1290,13 +1369,46 @@
qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
+ /*
+ * Don't use result dump status. The operation may not be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+ pr_err("ablk_cipher operation error. Status %x\n",
+ status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status |
+ pce_dev->ce_sps.producer_status) {
+ pr_err("ablk_cipher sps operation error. sps status %x %x\n",
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("ablk_cipher operation not done? Status %x, sps status %x %x\n",
+ status,
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+
+ } else {
+ result_status = 0;
+ }
+
if (pce_dev->mode == QCE_MODE_ECB) {
pce_dev->qce_cb(areq, NULL, NULL,
pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ result_status);
} else {
if (pce_dev->ce_sps.minor_version == 0) {
if (pce_dev->mode == QCE_MODE_CBC) {
@@ -1342,9 +1454,7 @@
(char *)(pce_dev->ce_sps.result->encr_cntr_iv),
sizeof(iv));
}
- pce_dev->qce_cb(areq, NULL, iv,
- pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ pce_dev->qce_cb(areq, NULL, iv, result_status);
}
return 0;
};
@@ -1394,6 +1504,45 @@
}
#endif
+
+static void _qce_dump_descr_fifos_fail(struct qce_device *pce_dev)
+{
+ int i, j, ents;
+ struct sps_iovec *iovec = pce_dev->ce_sps.in_transfer.iovec;
+ uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD;
+
+ printk(KERN_INFO "==============================================\n");
+ printk(KERN_INFO "CONSUMER (TX/IN/DEST) PIPE DESCRIPTOR\n");
+ printk(KERN_INFO "==============================================\n");
+ for (i = 0; i < pce_dev->ce_sps.in_transfer.iovec_count; i++) {
+ printk(KERN_INFO " [%d] addr=0x%x size=0x%x flags=0x%x\n", i,
+ iovec->addr, iovec->size, iovec->flags);
+ if (iovec->flags & cmd_flags) {
+ struct sps_command_element *pced;
+
+ pced = (struct sps_command_element *)
+ (GET_VIRT_ADDR(iovec->addr));
+ ents = iovec->size/(sizeof(struct sps_command_element));
+ for (j = 0; j < ents; j++) {
+ printk(KERN_INFO " [%d] [0x%x] 0x%x\n", j,
+ pced->addr, pced->data);
+ pced++;
+ }
+ }
+ iovec++;
+ }
+
+ printk(KERN_INFO "==============================================\n");
+ printk(KERN_INFO "PRODUCER (RX/OUT/SRC) PIPE DESCRIPTOR\n");
+ printk(KERN_INFO "==============================================\n");
+ iovec = pce_dev->ce_sps.out_transfer.iovec;
+ for (i = 0; i < pce_dev->ce_sps.out_transfer.iovec_count; i++) {
+ printk(KERN_INFO " [%d] addr=0x%x size=0x%x flags=0x%x\n", i,
+ iovec->addr, iovec->size, iovec->flags);
+ iovec++;
+ }
+}
+
static void _qce_sps_iovec_count_init(struct qce_device *pce_dev)
{
pce_dev->ce_sps.in_transfer.iovec_count = 0;
@@ -1492,6 +1641,7 @@
if (rc) {
pr_err("sps_xfr() fail (consumer pipe=0x%x) rc = %d,",
(u32)pce_dev->ce_sps.consumer.pipe, rc);
+ _qce_dump_descr_fifos_fail(pce_dev);
return rc;
}
rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
@@ -1993,6 +2143,9 @@
break;
}
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
@@ -2037,13 +2190,9 @@
if (mode == QCE_MODE_XTS) {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
} else {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
0, &pcl_info->auth_seg_size);
}
@@ -2130,6 +2279,9 @@
break;
}
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
@@ -2156,13 +2308,7 @@
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
NULL);
}
- /* Add dummy to align size to burst-size multiple */
- if (!mode_cbc) {
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
- 0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
- }
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_le, NULL);
@@ -2206,10 +2352,13 @@
auth_cfg = pdev->reg.auth_cfg_sha1;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA256:
@@ -2218,13 +2367,16 @@
auth_cfg = pdev->reg.auth_cfg_sha256;
iv_reg = 8;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA1_HMAC:
cmdlistptr->auth_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2233,10 +2385,13 @@
auth_cfg = pdev->reg.auth_cfg_hmac_sha1;
key_reg = 16;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_AEAD_SHA1_HMAC:
cmdlistptr->aead_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2245,13 +2400,16 @@
auth_cfg = pdev->reg.auth_cfg_aead_sha1_hmac;
key_reg = 16;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA256_HMAC:
cmdlistptr->auth_sha256_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2261,13 +2419,15 @@
key_reg = 16;
iv_reg = 8;
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_AES_CMAC:
if (key_128 == true) {
@@ -2285,13 +2445,16 @@
auth_cfg = pdev->reg.auth_cfg_cmac_256;
key_reg = 8;
}
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
default:
pr_err("Unknown algorithms %d received, exiting now\n", alg);
@@ -2395,10 +2558,13 @@
key_reg = 8;
}
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
NULL);
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index a09bb42..a18fb8b 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1650,6 +1650,10 @@
__func__);
goto error;
}
+ if (req->byteoffset >= AES_CE_BLOCK_SIZE) {
+ pr_err("%s: Invalid byte offset\n", __func__);
+ goto error;
+ }
}
/* Ensure zer ivlen for ECB mode */
if (req->ivlen > 0) {
@@ -1939,13 +1943,11 @@
podev->platform_support.bus_scale_table = NULL;
podev->platform_support.sha_hmac = 1;
- if (podev->ce_support.is_shared == false) {
- podev->platform_support.bus_scale_table =
- (struct msm_bus_scale_pdata *)
- msm_bus_cl_get_pdata(pdev);
- if (!podev->platform_support.bus_scale_table)
- pr_err("bus_scale_table is NULL\n");
- }
+ podev->platform_support.bus_scale_table =
+ (struct msm_bus_scale_pdata *)
+ msm_bus_cl_get_pdata(pdev);
+ if (!podev->platform_support.bus_scale_table)
+ pr_err("bus_scale_table is NULL\n");
} else {
platform_support =
(struct msm_ce_hw_support *)pdev->dev.platform_data;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index a4bb2f1..375516b 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -3393,13 +3393,11 @@
cp->platform_support.bus_scale_table = NULL;
cp->platform_support.sha_hmac = 1;
- if (cp->ce_support.is_shared == false) {
- cp->platform_support.bus_scale_table =
- (struct msm_bus_scale_pdata *)
- msm_bus_cl_get_pdata(pdev);
- if (!cp->platform_support.bus_scale_table)
- pr_warn("bus_scale_table is NULL\n");
- }
+ cp->platform_support.bus_scale_table =
+ (struct msm_bus_scale_pdata *)
+ msm_bus_cl_get_pdata(pdev);
+ if (!cp->platform_support.bus_scale_table)
+ pr_warn("bus_scale_table is NULL\n");
} else {
platform_support =
(struct msm_ce_hw_support *)pdev->dev.platform_data;
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 1be2702..e93e25c 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -297,6 +297,7 @@
#define CRYPTO_DOUT_SIZE_AVAIL_MASK (0x1F << CRYPTO_DOUT_SIZE_AVAIL)
#define CRYPTO_DIN_SIZE_AVAIL 21 /* bit 21-25 */
#define CRYPTO_DIN_SIZE_AVAIL_MASK (0x1F << CRYPTO_DIN_SIZE_AVAIL)
+#define CRYPTO_HSD_ERR 20
#define CRYPTO_ACCESS_VIOL 19
#define CRYPTO_PIPE_ACTIVE_ERR 18
#define CRYPTO_CFG_CHNG_ERR 17
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index 193f4d4..e7f7836 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -115,6 +115,7 @@
dev_dbg(dev, "Release buffer %p\n", buffer);
/* release memory */
dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+ sg_free_table(info->table);
/* release sg table */
kfree(info->table);
kfree(info);
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index e1b3eea..b3960b2 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -154,6 +154,7 @@
dev_dbg(dev, "Release buffer %p\n", buffer);
/* release memory */
dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+ sg_free_table(info->table);
/* release sg table */
kfree(info->table);
kfree(info);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index bc9bddd..b1c1c5d 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -42,6 +42,7 @@
*/
struct ion_iommu_priv_data {
struct page **pages;
+ unsigned int pages_uses_vmalloc;
int nrpages;
unsigned long size;
};
@@ -118,6 +119,7 @@
unsigned int npages_to_vmap, total_pages, num_large_pages = 0;
unsigned long size_remaining = PAGE_ALIGN(size);
unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
+ unsigned int page_tbl_size;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -139,8 +141,24 @@
data->size = PFN_ALIGN(size);
data->nrpages = data->size >> PAGE_SHIFT;
- data->pages = kzalloc(sizeof(struct page *)*data->nrpages,
- GFP_KERNEL);
+ data->pages_uses_vmalloc = 0;
+ page_tbl_size = sizeof(struct page *) * data->nrpages;
+
+ if (page_tbl_size > SZ_8K) {
+ /*
+ * Do fallback to ensure we have a balance between
+ * performance and availability.
+ */
+ data->pages = kmalloc(page_tbl_size,
+ __GFP_COMP | __GFP_NORETRY |
+ __GFP_NO_KSWAPD | __GFP_NOWARN);
+ if (!data->pages) {
+ data->pages = vmalloc(page_tbl_size);
+ data->pages_uses_vmalloc = 1;
+ }
+ } else {
+ data->pages = kmalloc(page_tbl_size, GFP_KERNEL);
+ }
if (!data->pages) {
ret = -ENOMEM;
goto err_free_data;
@@ -222,7 +240,10 @@
kfree(buffer->sg_table);
buffer->sg_table = 0;
err1:
- kfree(data->pages);
+ if (data->pages_uses_vmalloc)
+ vfree(data->pages);
+ else
+ kfree(data->pages);
err_free_data:
kfree(data);
@@ -253,7 +274,10 @@
sg_free_table(table);
kfree(table);
table = 0;
- kfree(data->pages);
+ if (data->pages_uses_vmalloc)
+ vfree(data->pages);
+ else
+ kfree(data->pages);
kfree(data);
}
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 3441afa..fc66328 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -25,6 +25,7 @@
adreno_drawctxt.o \
adreno_postmortem.o \
adreno_snapshot.o \
+ adreno_coresight.o \
adreno_a2xx.o \
adreno_a2xx_trace.o \
adreno_a2xx_snapshot.o \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 5f435f3..0c398c4 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -165,8 +165,16 @@
#define A3XX_RBBM_PERFCTR_PWR_0_HI 0x0EB
#define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
#define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
-#define A3XX_RBBM_DEBUG_BUS_CTL 0x111
-#define A3XX_RBBM_DEBUG_BUS_DATA_STATUS 0x112
+#define A3XX_RBBM_DEBUG_BUS_CTL 0x111
+#define A3XX_RBBM_DEBUG_BUS_DATA_STATUS 0x112
+#define A3XX_RBBM_DEBUG_BUS_STB_CTL0 0x11B
+#define A3XX_RBBM_DEBUG_BUS_STB_CTL1 0x11C
+#define A3XX_RBBM_INT_TRACE_BUS_CTL 0x11D
+#define A3XX_RBBM_EXT_TRACE_BUS_CTL 0x11E
+#define A3XX_RBBM_EXT_TRACE_STOP_CNT 0x11F
+#define A3XX_RBBM_EXT_TRACE_START_CNT 0x120
+#define A3XX_RBBM_EXT_TRACE_PERIOD_CNT 0x121
+#define A3XX_RBBM_EXT_TRACE_CMD 0x122
/* Following two are same as on A2XX, just in a different place */
#define A3XX_CP_PFP_UCODE_ADDR 0x1C9
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a4f60f9..aad2882 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/delay.h>
+#include <linux/of_coresight.h>
#include <mach/socinfo.h>
#include <mach/msm_bus_board.h>
@@ -1522,6 +1523,9 @@
if (ret)
goto err;
+ pdata->coresight_pdata = of_get_coresight_platform_data(&pdev->dev,
+ pdev->dev.of_node);
+
pdev->dev.platform_data = pdata;
return 0;
@@ -1595,6 +1599,7 @@
adreno_probe(struct platform_device *pdev)
{
struct kgsl_device *device;
+ struct kgsl_device_platform_data *pdata = NULL;
struct adreno_device *adreno_dev;
int status = -EINVAL;
bool is_dt;
@@ -1625,6 +1630,10 @@
kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY);
device->flags &= ~KGSL_FLAGS_SOFT_RESET;
+ pdata = kgsl_device_get_drvdata(device);
+
+ adreno_coresight_init(pdev);
+
return 0;
error_close_rb:
@@ -1643,6 +1652,8 @@
device = (struct kgsl_device *)pdev->id_entry->driver_data;
adreno_dev = ADRENO_DEVICE(device);
+ adreno_coresight_remove(pdev);
+
kgsl_pwrscale_detach_policy(device);
kgsl_pwrscale_close(device);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index fa892b9..77b654b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -80,6 +80,15 @@
ADRENO_REV_A305B = 335,
};
+enum coresight_debug_reg {
+ DEBUG_BUS_CTL,
+ TRACE_STOP_CNT,
+ TRACE_START_CNT,
+ TRACE_PERIOD_CNT,
+ TRACE_CMD,
+ TRACE_BUS_CTL,
+};
+
struct adreno_gpudev;
struct adreno_device {
@@ -187,6 +196,10 @@
uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
unsigned int group, unsigned int counter,
unsigned int offset);
+ int (*coresight_enable) (struct kgsl_device *device);
+ void (*coresight_disable) (struct kgsl_device *device);
+ void (*coresight_config_debug_reg) (struct kgsl_device *device,
+ int debug_reg, unsigned int val);
};
/*
@@ -269,6 +282,10 @@
extern unsigned int ft_detect_regs[];
extern const unsigned int ft_detect_regs_count;
+int adreno_coresight_enable(struct coresight_device *csdev);
+void adreno_coresight_disable(struct coresight_device *csdev);
+void adreno_coresight_remove(struct platform_device *pdev);
+int adreno_coresight_init(struct platform_device *pdev);
int adreno_idle(struct kgsl_device *device);
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index a4b3121..1cdc87a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3235,6 +3235,108 @@
adreno_dev->gpu_cycles = 0;
}
+/**
+ * a3xx_coresight_enable() - Enables debugging through coresight
+ * debug bus for adreno a3xx devices.
+ * @device: Pointer to GPU device structure
+ */
+int a3xx_coresight_enable(struct kgsl_device *device)
+{
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0001093F);
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0,
+ 0x00000000);
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1,
+ 0xFFFFFFFE);
+ adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL,
+ 0x00201111);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+ 0x89100010);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+ 0x00017fff);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+ 0x0001000f);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT ,
+ 0x0001ffff);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD,
+ 0x00000001);
+ kgsl_active_count_put(device);
+ }
+ mutex_unlock(&device->mutex);
+ return 0;
+}
+
+/**
+ * a3xx_coresight_disable() - Disables debugging through coresight
+ * debug bus for adreno a3xx devices.
+ * @device: Pointer to GPU device structure
+ */
+void a3xx_coresight_disable(struct kgsl_device *device)
+{
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT, 0x0);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT , 0x0);
+ adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD, 0x0);
+ kgsl_active_count_put(device);
+ }
+ mutex_unlock(&device->mutex);
+}
+
+static void a3xx_coresight_write_reg(struct kgsl_device *device,
+ unsigned int wordoffset, unsigned int val)
+{
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ adreno_regwrite(device, wordoffset, val);
+ kgsl_active_count_put(device);
+ }
+ mutex_unlock(&device->mutex);
+}
+
+void a3xx_coresight_config_debug_reg(struct kgsl_device *device,
+ int debug_reg, unsigned int val)
+{
+ switch (debug_reg) {
+
+ case DEBUG_BUS_CTL:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_DEBUG_BUS_CTL, val);
+ break;
+
+ case TRACE_STOP_CNT:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+ val);
+ break;
+
+ case TRACE_START_CNT:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+ val);
+ break;
+
+ case TRACE_PERIOD_CNT:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT,
+ val);
+ break;
+
+ case TRACE_CMD:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_CMD, val);
+ break;
+
+ case TRACE_BUS_CTL:
+ a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+ val);
+ break;
+ }
+
+}
+
/*
* Define the available perfcounter groups - these get used by
* adreno_perfcounter_get and adreno_perfcounter_put
@@ -3381,4 +3483,7 @@
.snapshot = a3xx_snapshot,
.perfcounter_enable = a3xx_perfcounter_enable,
.perfcounter_read = a3xx_perfcounter_read,
+ .coresight_enable = a3xx_coresight_enable,
+ .coresight_disable = a3xx_coresight_disable,
+ .coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
};
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
new file mode 100644
index 0000000..e18568d
--- /dev/null
+++ b/drivers/gpu/msm/adreno_coresight.c
@@ -0,0 +1,219 @@
+/* Copyright (c) 2013, 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/clk.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/memory_alloc.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "kgsl.h"
+#include "kgsl_device.h"
+#include "adreno.h"
+
+struct coresight_attr {
+ struct device_attribute attr;
+ int regname;
+};
+
+#define CORESIGHT_CREATE_REG_ATTR(_attrname, _regname) \
+ struct coresight_attr coresight_attr_##_attrname = \
+ { __ATTR(_attrname, S_IRUGO | S_IWUSR, gfx_show_reg, gfx_store_reg),\
+ _regname}
+
+/**
+ * adreno_coresight_enable() - Generic function to enable coresight debugging
+ * @csdev: Pointer to coresight's device struct
+ *
+ * This is a generic function to enable coresight debug bus on adreno
+ * devices. This should be used in all cases of enabling
+ * coresight debug bus for adreno devices. This function in turn calls
+ * the adreno device specific function through gpudev hook.
+ * This function is registered as the coresight enable function
+ * with coresight driver. It should only be called through coresight driver
+ * as that would ensure that the necessary setup required to be done
+ * on coresight driver's part is also done.
+ */
+int adreno_coresight_enable(struct coresight_device *csdev)
+{
+ struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* Check if coresight compatible device, return error otherwise */
+ if (adreno_dev->gpudev->coresight_enable)
+ return adreno_dev->gpudev->coresight_enable(device);
+ else
+ return -ENODEV;
+}
+
+/**
+ * adreno_coresight_disable() - Generic function to disable coresight debugging
+ * @csdev: Pointer to coresight's device struct
+ *
+ * This is a generic function to disable coresight debug bus on adreno
+ * devices. This should be used in all cases of disabling
+ * coresight debug bus for adreno devices. This function in turn calls
+ * the adreno device specific function through the gpudev hook.
+ * This function is registered as the coresight disable function
+ * with coresight driver. It should only be called through coresight driver
+ * as that would ensure that the necessary setup required to be done on
+ * coresight driver's part is also done.
+ */
+void adreno_coresight_disable(struct coresight_device *csdev)
+{
+ struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* Check if coresight compatible device, bail otherwise */
+ if (adreno_dev->gpudev->coresight_disable)
+ return adreno_dev->gpudev->coresight_disable(device);
+}
+
+static const struct coresight_ops_source adreno_coresight_ops_source = {
+ .enable = adreno_coresight_enable,
+ .disable = adreno_coresight_disable,
+};
+
+static const struct coresight_ops adreno_coresight_cs_ops = {
+ .source_ops = &adreno_coresight_ops_source,
+};
+
+void adreno_coresight_remove(struct platform_device *pdev)
+{
+ struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+ coresight_unregister(pdata->csdev);
+}
+
+static ssize_t coresight_read_reg(struct kgsl_device *device,
+ unsigned int offset, char *buf)
+{
+ unsigned int regval = 0;
+
+ mutex_lock(&device->mutex);
+ if (!kgsl_active_count_get(device)) {
+ adreno_regread(device, offset, ®val);
+ kgsl_active_count_put(device);
+ }
+ mutex_unlock(&device->mutex);
+ return snprintf(buf, PAGE_SIZE, "0x%X", regval);
+}
+
+static inline unsigned int coresight_convert_reg(const char *buf)
+{
+ long regval = 0;
+ int rv = 0;
+
+ rv = kstrtoul(buf, 16, ®val);
+ if (!rv)
+ return (unsigned int)regval;
+ else
+ return rv;
+}
+
+static ssize_t gfx_show_reg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kgsl_device *device = dev_get_drvdata(dev->parent);
+ struct coresight_attr *csight_attr = container_of(attr,
+ struct coresight_attr, attr);
+ return coresight_read_reg(device, csight_attr->regname, buf);
+}
+
+static ssize_t gfx_store_reg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct kgsl_device *device = dev_get_drvdata(dev->parent);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct coresight_attr *csight_attr = container_of(attr,
+ struct coresight_attr, attr);
+ unsigned int regval = 0;
+
+ regval = coresight_convert_reg(buf);
+
+ if (adreno_dev->gpudev->coresight_config_debug_reg)
+ adreno_dev->gpudev->coresight_config_debug_reg(device,
+ csight_attr->regname, regval);
+ return size;
+}
+
+CORESIGHT_CREATE_REG_ATTR(config_debug_bus, DEBUG_BUS_CTL);
+CORESIGHT_CREATE_REG_ATTR(config_trace_stop_cnt, TRACE_STOP_CNT);
+CORESIGHT_CREATE_REG_ATTR(config_trace_start_cnt, TRACE_START_CNT);
+CORESIGHT_CREATE_REG_ATTR(config_trace_period_cnt, TRACE_PERIOD_CNT);
+CORESIGHT_CREATE_REG_ATTR(config_trace_cmd, TRACE_CMD);
+CORESIGHT_CREATE_REG_ATTR(config_trace_bus_ctl, TRACE_BUS_CTL);
+
+static struct attribute *gfx_attrs[] = {
+ &coresight_attr_config_debug_bus.attr.attr,
+ &coresight_attr_config_trace_start_cnt.attr.attr,
+ &coresight_attr_config_trace_stop_cnt.attr.attr,
+ &coresight_attr_config_trace_period_cnt.attr.attr,
+ &coresight_attr_config_trace_cmd.attr.attr,
+ &coresight_attr_config_trace_bus_ctl.attr.attr,
+ NULL,
+};
+
+static struct attribute_group gfx_attr_grp = {
+ .attrs = gfx_attrs,
+};
+
+static const struct attribute_group *gfx_attr_grps[] = {
+ &gfx_attr_grp,
+ NULL,
+};
+
+int adreno_coresight_init(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct coresight_desc *desc;
+
+ if (IS_ERR_OR_NULL(pdata->coresight_pdata))
+ return -ENODATA;
+
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+
+ desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+ desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS;
+ desc->ops = &adreno_coresight_cs_ops;
+ desc->pdata = pdata->coresight_pdata;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->groups = gfx_attr_grps;
+ pdata->csdev = coresight_register(desc);
+ if (IS_ERR(pdata->csdev)) {
+ ret = PTR_ERR(pdata->csdev);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ devm_kfree(dev, desc);
+ return ret;
+}
+
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 992f88d..9de3410 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -29,6 +29,8 @@
#include <linux/io.h>
#include <mach/socinfo.h>
#include <linux/mman.h>
+#include <linux/sort.h>
+#include <asm/cacheflush.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -674,7 +676,7 @@
list_del(&private->list);
mutex_unlock(&kgsl_driver.process_mutex);
- if (private->kobj.parent)
+ if (private->kobj.ktype)
kgsl_process_uninit_sysfs(private);
if (private->debug_root)
debugfs_remove_recursive(private->debug_root);
@@ -791,7 +793,7 @@
}
}
- if (!private->kobj.parent)
+ if (!private->kobj.ktype)
kgsl_process_init_sysfs(private);
if (!private->debug_root)
kgsl_process_init_debugfs(private);
@@ -2104,6 +2106,97 @@
return ret;
}
+static int mem_id_cmp(const void *_a, const void *_b)
+{
+ const unsigned int *a = _a, *b = _b;
+ int cmp = a - b;
+ return (cmp < 0) ? -1 : (cmp > 0);
+}
+
+static long
+kgsl_ioctl_gpumem_sync_cache_bulk(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ int i;
+ struct kgsl_gpumem_sync_cache_bulk *param = data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ unsigned int id, last_id = 0, *id_list = NULL, actual_count = 0;
+ struct kgsl_mem_entry **entries = NULL;
+ long ret = 0;
+ size_t op_size = 0;
+ bool full_flush = false;
+
+ if (param->id_list == NULL || param->count == 0
+ || param->count > (UINT_MAX/sizeof(unsigned int)))
+ return -EINVAL;
+
+ id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
+ if (id_list == NULL)
+ return -ENOMEM;
+
+ entries = kzalloc(param->count * sizeof(*entries), GFP_KERNEL);
+ if (entries == NULL) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ if (copy_from_user(id_list, param->id_list,
+ param->count * sizeof(unsigned int))) {
+ ret = -EFAULT;
+ goto end;
+ }
+ /* sort the ids so we can weed out duplicates */
+ sort(id_list, param->count, sizeof(int), mem_id_cmp, NULL);
+
+ for (i = 0; i < param->count; i++) {
+ unsigned int cachemode;
+ struct kgsl_mem_entry *entry = NULL;
+
+ id = id_list[i];
+ /* skip 0 ids or duplicates */
+ if (id == last_id)
+ continue;
+
+ entry = kgsl_sharedmem_find_id(private, id);
+ if (entry == NULL)
+ continue;
+
+ /* skip uncached memory */
+ cachemode = kgsl_memdesc_get_cachemode(&entry->memdesc);
+ if (cachemode != KGSL_CACHEMODE_WRITETHROUGH &&
+ cachemode != KGSL_CACHEMODE_WRITEBACK) {
+ kgsl_mem_entry_put(entry);
+ continue;
+ }
+
+ op_size += entry->memdesc.size;
+ entries[actual_count++] = entry;
+
+ /* If we exceed the breakeven point, flush the entire cache */
+ if (op_size >= kgsl_driver.full_cache_threshold &&
+ param->op == KGSL_GPUMEM_CACHE_FLUSH) {
+ full_flush = true;
+ break;
+ }
+ last_id = id;
+ }
+ if (full_flush) {
+ trace_kgsl_mem_sync_full_cache(actual_count, op_size,
+ param->op);
+ __cpuc_flush_kern_all();
+ }
+
+ for (i = 0; i < actual_count; i++) {
+ if (!full_flush)
+ _kgsl_gpumem_sync_cache(entries[i], param->op);
+ kgsl_mem_entry_put(entries[i]);
+ }
+end:
+ kfree(entries);
+ kfree(id_list);
+ return ret;
+}
+
/* Legacy cache function, does a flush (clean + invalidate) */
static long
@@ -2510,6 +2603,8 @@
kgsl_ioctl_gpumem_get_info, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
kgsl_ioctl_gpumem_sync_cache, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
+ kgsl_ioctl_gpumem_sync_cache_bulk, 0),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2952,6 +3047,11 @@
.devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
.memfree_hist_mutex =
__MUTEX_INITIALIZER(kgsl_driver.memfree_hist_mutex),
+ /*
+ * Full cache flushes are faster than line by line on at least
+ * 8064 and 8974 once the region to be flushed is > 16mb.
+ */
+ .full_cache_threshold = SZ_16M,
};
EXPORT_SYMBOL(kgsl_driver);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index c7cbaf8..de3f619 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -134,6 +134,7 @@
unsigned int mapped_max;
unsigned int histogram[16];
} stats;
+ unsigned int full_cache_threshold;
};
extern struct kgsl_driver kgsl_driver;
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index 3b01e54..a1fc5a2 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -268,7 +268,8 @@
* timestamp on the event has passed - return that up a layer
*/
- return device->ftbl->next_event(device, event);
+ if (device->ftbl->next_event)
+ return device->ftbl->next_event(device, event);
}
return 0;
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index e071650..05d24e9 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -76,6 +76,10 @@
},
};
+static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+ int requested_state);
+static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
+
/* Update the elapsed time at a particular clock level
* if the device is active(on_time = true).Otherwise
* store it as sleep time.
@@ -671,6 +675,87 @@
return snprintf(buf, PAGE_SIZE, "%d\n", device->reset_counter);
}
+static void __force_on(struct kgsl_device *device, int flag, int on)
+{
+ if (on) {
+ switch (flag) {
+ case KGSL_PWRFLAGS_CLK_ON:
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON,
+ KGSL_STATE_ACTIVE);
+ break;
+ case KGSL_PWRFLAGS_AXI_ON:
+ kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
+ break;
+ }
+ set_bit(flag, &device->pwrctrl.ctrl_flags);
+ } else {
+ clear_bit(flag, &device->pwrctrl.ctrl_flags);
+ }
+}
+
+static int __force_on_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, int flag)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int i = test_bit(flag, &device->pwrctrl.ctrl_flags);
+ return snprintf(buf, PAGE_SIZE, "%d\n", i);
+}
+
+static int __force_on_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count,
+ int flag)
+{
+ char temp[20];
+ unsigned long val;
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int rc;
+
+ if (device == NULL)
+ return 0;
+
+ snprintf(temp, sizeof(temp), "%.*s",
+ (int)min(count, sizeof(temp) - 1), buf);
+ rc = kstrtoul(temp, 0, &val);
+ if (rc)
+ return rc;
+
+ mutex_lock(&device->mutex);
+ __force_on(device, flag, val);
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_force_clk_on_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return __force_on_show(dev, attr, buf, KGSL_PWRFLAGS_CLK_ON);
+}
+
+static int kgsl_pwrctrl_force_clk_on_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_CLK_ON);
+}
+
+static int kgsl_pwrctrl_force_bus_on_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return __force_on_show(dev, attr, buf, KGSL_PWRFLAGS_AXI_ON);
+}
+
+static int kgsl_pwrctrl_force_bus_on_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_AXI_ON);
+}
+
DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
kgsl_pwrctrl_max_gpuclk_store);
@@ -702,6 +787,12 @@
DEVICE_ATTR(reset_count, 0444,
kgsl_pwrctrl_reset_count_show,
NULL);
+DEVICE_ATTR(force_clk_on, 0644,
+ kgsl_pwrctrl_force_clk_on_show,
+ kgsl_pwrctrl_force_clk_on_store);
+DEVICE_ATTR(force_bus_on, 0644,
+ kgsl_pwrctrl_force_bus_on_show,
+ kgsl_pwrctrl_force_bus_on_store);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -717,6 +808,8 @@
&dev_attr_num_pwrlevels,
&dev_attr_pmqos_latency,
&dev_attr_reset_count,
+ &dev_attr_force_clk_on,
+ &dev_attr_force_bus_on,
NULL
};
@@ -766,11 +859,15 @@
}
}
-void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
int requested_state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int i = 0;
+
+ if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->ctrl_flags))
+ return;
+
if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_CLK_ON,
&pwr->power_flags)) {
@@ -824,10 +921,13 @@
}
}
-void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
+static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->ctrl_flags))
+ return;
+
if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
&pwr->power_flags)) {
@@ -858,7 +958,7 @@
}
}
-void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
+static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
@@ -1454,6 +1554,8 @@
}
if (ret == 0)
device->active_cnt++;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return ret;
}
EXPORT_SYMBOL(kgsl_active_count_get);
@@ -1482,6 +1584,8 @@
}
device->active_cnt++;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return 0;
}
EXPORT_SYMBOL(kgsl_active_count_get_light);
@@ -1504,6 +1608,8 @@
kgsl_pwrscale_idle(device);
if (device->active_cnt > 1) {
device->active_cnt--;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return;
}
@@ -1520,6 +1626,8 @@
}
device->active_cnt--;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
if (device->active_cnt == 0)
complete(&device->suspend_gate);
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 2b986c8..7bc849d 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -69,6 +69,7 @@
struct clk *ebi1_clk;
struct clk *grp_clks[KGSL_MAX_CLKS];
unsigned long power_flags;
+ unsigned long ctrl_flags;
struct kgsl_pwrlevel pwrlevels[KGSL_MAX_PWRLEVELS];
unsigned int active_pwrlevel;
int thermal_pwrlevel;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b9bc432..1691762 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -234,6 +234,29 @@
return len;
}
+static int kgsl_drv_full_cache_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned int thresh;
+ ret = sscanf(buf, "%d", &thresh);
+ if (ret != 1)
+ return count;
+
+ kgsl_driver.full_cache_threshold = thresh;
+
+ return count;
+}
+
+static int kgsl_drv_full_cache_threshold_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ kgsl_driver.full_cache_threshold);
+}
+
DEVICE_ATTR(vmalloc, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(vmalloc_max, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(page_alloc, 0444, kgsl_drv_memstat_show, NULL);
@@ -243,6 +266,9 @@
DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(mapped_max, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(histogram, 0444, kgsl_drv_histogram_show, NULL);
+DEVICE_ATTR(full_cache_threshold, 0644,
+ kgsl_drv_full_cache_threshold_show,
+ kgsl_drv_full_cache_threshold_store);
static const struct device_attribute *drv_attr_list[] = {
&dev_attr_vmalloc,
@@ -254,6 +280,7 @@
&dev_attr_mapped,
&dev_attr_mapped_max,
&dev_attr_histogram,
+ &dev_attr_full_cache_threshold,
NULL
};
@@ -598,7 +625,7 @@
gfp_mask |= __GFP_COMP | __GFP_NORETRY |
__GFP_NO_KSWAPD | __GFP_NOWARN;
else
- gfp_mask |= GFP_KERNEL | __GFP_NORETRY;
+ gfp_mask |= GFP_KERNEL;
page = alloc_pages(gfp_mask, get_order(page_size));
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f7ee3c..6917883 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -539,6 +539,33 @@
)
);
+TRACE_EVENT(kgsl_mem_sync_full_cache,
+
+ TP_PROTO(unsigned int num_bufs, unsigned int bulk_size,
+ unsigned int op),
+
+ TP_ARGS(num_bufs, bulk_size, op),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, num_bufs)
+ __field(unsigned int, bulk_size)
+ __field(unsigned int, op)
+ ),
+
+ TP_fast_assign(
+ __entry->num_bufs = num_bufs;
+ __entry->bulk_size = bulk_size;
+ __entry->op = op;
+ ),
+
+ TP_printk(
+ "num_bufs=%d bulk_size=%d op=%c%c",
+ __entry->num_bufs, __entry->bulk_size,
+ (__entry->op & KGSL_GPUMEM_CACHE_CLEAN) ? 'c' : '.',
+ (__entry->op & KGSL_GPUMEM_CACHE_INV) ? 'i' : '.'
+ )
+);
+
DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template,
TP_PROTO(struct kgsl_device *device, struct kgsl_mem_entry *mem_entry,
@@ -739,6 +766,30 @@
__entry->id, __entry->ts, __entry->age)
);
+TRACE_EVENT(kgsl_active_count,
+
+ TP_PROTO(struct kgsl_device *device, unsigned long ip),
+
+ TP_ARGS(device, ip),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, count)
+ __field(unsigned long, ip)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->count = device->active_cnt;
+ __entry->ip = ip;
+ ),
+
+ TP_printk(
+ "d_name=%s active_cnt=%x func=%pf",
+ __get_str(device_name), __entry->count, (void *) __entry->ip
+ )
+);
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index b3b3b5e..4306b1d 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -83,6 +83,14 @@
#define QPNP_VADC_M1_LOW_THR_MSB 0x6a
#define QPNP_VADC_M1_HIGH_THR_LSB 0x6b
#define QPNP_VADC_M1_HIGH_THR_MSB 0x6c
+#define QPNP_VADC_ACCESS 0xd0
+#define QPNP_VADC_ACCESS_DATA 0xa5
+#define QPNP_VADC_PERH_RESET_CTL3 0xda
+#define QPNP_FOLLOW_OTST2_RB BIT(3)
+#define QPNP_FOLLOW_WARM_RB BIT(2)
+#define QPNP_FOLLOW_SHUTDOWN1_RB BIT(1)
+#define QPNP_FOLLOW_SHUTDOWN2_RB BIT(0)
+
#define QPNP_INT_TEST_VAL 0xE1
#define QPNP_VADC_DATA0 0x60
@@ -150,6 +158,40 @@
return 0;
}
+static int32_t qpnp_vadc_warm_rst_configure(void)
+{
+ int rc = 0;
+ u8 data = 0;
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("VADC write access failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_read_reg(QPNP_VADC_PERH_RESET_CTL3, &data);
+ if (rc < 0) {
+ pr_err("VADC perh reset ctl3 read failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("VADC write access failed\n");
+ return rc;
+ }
+
+ data |= QPNP_FOLLOW_WARM_RB;
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_PERH_RESET_CTL3, data);
+ if (rc < 0) {
+ pr_err("VADC perh reset ctl3 write failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int32_t qpnp_vadc_enable(bool state)
{
int rc = 0;
@@ -1126,6 +1168,12 @@
}
vadc->id = fab_id;
+ rc = qpnp_vadc_warm_rst_configure();
+ if (rc < 0) {
+ pr_err("Setting perp reset on warm reset failed %d\n", rc);
+ return rc;
+ }
+
vadc->vadc_initialized = true;
vadc->vadc_iadc_sync_lock = false;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a77dacb..b96349e 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -37,6 +37,7 @@
#include <linux/of_gpio.h>
#include <mach/board.h>
#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.2");
@@ -142,6 +143,22 @@
.pull = GPIOMUX_PULL_NONE,
};
+/**
+ * qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
+ *
+ * @client_hdl when zero, client is not registered with the bus scaling driver,
+ * and bus scaling functionality should not be used. When non zero, it
+ * is a bus scaling client id and may be used to vote for clock path.
+ * @reg_err when true, registration error was detected and an error message was
+ * logged. i2c will attempt to re-register but will log error only once.
+ * once registration succeed, the flag is set to false.
+ */
+struct qup_i2c_clk_path_vote {
+ u32 client_hdl;
+ struct msm_bus_scale_pdata *pdata;
+ bool reg_err;
+};
+
struct qup_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
@@ -172,6 +189,7 @@
struct mutex mlock;
void *complete;
int i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
+ struct qup_i2c_clk_path_vote clk_path_vote;
};
#ifdef DEBUG
@@ -333,11 +351,160 @@
mb();
}
+#define MSM_I2C_CLK_PATH_SUSPEND (0)
+#define MSM_I2C_CLK_PATH_RESUME (1)
+#define MSM_I2C_CLK_PATH_MAX_BW(dev) ((dev->pdata->src_clk_rate * 8) / 1000)
+
+static int i2c_qup_clk_path_init(struct platform_device *pdev,
+ struct qup_i2c_dev *dev)
+{
+ struct msm_bus_vectors *paths = NULL;
+ struct msm_bus_paths *usecases = NULL;
+
+ if (!dev->pdata->master_id)
+ return 0;
+
+ dev_dbg(&pdev->dev, "initialises bus-scaling clock voting");
+
+ paths = devm_kzalloc(&pdev->dev, sizeof(*paths) * 2, GFP_KERNEL);
+ if (!paths) {
+ dev_err(&pdev->dev,
+ "msm_bus_paths.paths memory allocation failed");
+ return -ENOMEM;
+ }
+
+ usecases = devm_kzalloc(&pdev->dev, sizeof(*usecases) * 2, GFP_KERNEL);
+ if (!usecases) {
+ dev_err(&pdev->dev,
+ "msm_bus_scale_pdata.usecases memory allocation failed");
+ goto path_init_err;
+ }
+
+ dev->clk_path_vote.pdata = devm_kzalloc(&pdev->dev,
+ sizeof(*dev->clk_path_vote.pdata),
+ GFP_KERNEL);
+ if (!dev->clk_path_vote.pdata) {
+ dev_err(&pdev->dev,
+ "msm_bus_scale_pdata memory allocation failed");
+ goto path_init_err;
+ }
+
+ paths[MSM_I2C_CLK_PATH_SUSPEND] = (struct msm_bus_vectors) {
+ dev->pdata->master_id, MSM_BUS_SLAVE_EBI_CH0, 0, 0
+ };
+
+ paths[MSM_I2C_CLK_PATH_RESUME] = (struct msm_bus_vectors) {
+ dev->pdata->master_id, MSM_BUS_SLAVE_EBI_CH0, 0,
+ MSM_I2C_CLK_PATH_MAX_BW(dev)
+ };
+
+ usecases[MSM_I2C_CLK_PATH_SUSPEND] = (struct msm_bus_paths) {
+ .num_paths = 1,
+ .vectors = &paths[MSM_I2C_CLK_PATH_SUSPEND],
+ };
+
+ usecases[MSM_I2C_CLK_PATH_RESUME] = (struct msm_bus_paths) {
+ .num_paths = 1,
+ .vectors = &paths[MSM_I2C_CLK_PATH_RESUME],
+ };
+
+ *dev->clk_path_vote.pdata = (struct msm_bus_scale_pdata) {
+ .active_only = dev->pdata->active_only,
+ .name = pdev->name,
+ .num_usecases = 2,
+ .usecase = usecases,
+ };
+
+ return 0;
+
+path_init_err:
+ devm_kfree(&pdev->dev, paths);
+ devm_kfree(&pdev->dev, usecases);
+ devm_kfree(&pdev->dev, dev->clk_path_vote.pdata);
+ dev->clk_path_vote.pdata = NULL;
+ return -ENOMEM;
+}
+
+static void i2c_qup_clk_path_teardown(struct qup_i2c_dev *dev)
+{
+ if (dev->clk_path_vote.client_hdl) {
+ msm_bus_scale_unregister_client(dev->clk_path_vote.client_hdl);
+ dev->clk_path_vote.client_hdl = 0;
+ }
+}
+
+static void i2c_qup_clk_path_vote(struct qup_i2c_dev *dev)
+{
+ if (dev->clk_path_vote.client_hdl)
+ msm_bus_scale_client_update_request(
+ dev->clk_path_vote.client_hdl,
+ MSM_I2C_CLK_PATH_RESUME);
+}
+
+static void i2c_qup_clk_path_unvote(struct qup_i2c_dev *dev)
+{
+ if (dev->clk_path_vote.client_hdl)
+ msm_bus_scale_client_update_request(
+ dev->clk_path_vote.client_hdl,
+ MSM_I2C_CLK_PATH_SUSPEND);
+}
+
+/**
+ * i2c_qup_clk_path_postponed_register: reg with bus-scaling after it is probed
+ *
+ * Workaround: i2c driver may be probed before the bus scaling driver. Thus,
+ * this function should be called not from probe but from a later context.
+ * This function may be called more then once before register succeed. At
+ * this case only one error message will be logged. At boot time all clocks
+ * are on, so earlier i2c transactions should succeed.
+ */
+static void i2c_qup_clk_path_postponed_register(struct qup_i2c_dev *dev)
+{
+ /*
+ * bail out if path voting is diabled (master_id == 0) or if it is
+ * already registered (client_hdl != 0)
+ */
+ if (!dev->pdata->master_id || dev->clk_path_vote.client_hdl)
+ return;
+
+ dev->clk_path_vote.client_hdl = msm_bus_scale_register_client(
+ dev->clk_path_vote.pdata);
+
+ if (dev->clk_path_vote.client_hdl) {
+ if (dev->clk_path_vote.reg_err) {
+ /* log a success message if an error msg was logged */
+ dev->clk_path_vote.reg_err = false;
+ dev_info(dev->dev,
+ "msm_bus_scale_register_client(mstr-id:%d "
+ "actv-only:%d):0x%x",
+ dev->pdata->master_id, dev->pdata->active_only,
+ dev->clk_path_vote.client_hdl);
+ }
+
+ if (dev->pdata->active_only)
+ i2c_qup_clk_path_vote(dev);
+ } else {
+ /* guard to log only one error on multiple failure */
+ if (!dev->clk_path_vote.reg_err) {
+ dev->clk_path_vote.reg_err = true;
+
+ dev_info(dev->dev,
+ "msm_bus_scale_register_client(mstr-id:%d "
+ "actv-only:%d):0",
+ dev->pdata->master_id, dev->pdata->active_only);
+ }
+ }
+}
+
static void
qup_i2c_pwr_mgmt(struct qup_i2c_dev *dev, unsigned int state)
{
dev->pwr_state = state;
if (state != 0) {
+ i2c_qup_clk_path_postponed_register(dev);
+ if (!dev->pdata->active_only)
+ i2c_qup_clk_path_vote(dev);
+
clk_prepare_enable(dev->clk);
if (!dev->pdata->keep_ahb_clk_on)
clk_prepare_enable(dev->pclk);
@@ -347,6 +514,8 @@
qup_config_core_on_en(dev);
if (!dev->pdata->keep_ahb_clk_on)
clk_disable_unprepare(dev->pclk);
+ if (!dev->pdata->active_only)
+ i2c_qup_clk_path_unvote(dev);
}
}
@@ -1099,11 +1268,12 @@
enum msm_i2c_dt_entry_type {
DT_U32,
DT_GPIO,
+ DT_BOOL,
};
struct msm_i2c_dt_to_pdata_map {
const char *dt_name;
- int *ptr_data;
+ void *ptr_data;
enum msm_i2c_dt_entry_status status;
enum msm_i2c_dt_entry_type type;
int default_val;
@@ -1119,28 +1289,42 @@
{"qcom,i2c-bus-freq", &pdata->clk_freq , DT_REQUIRED , DT_U32 , 0},
{"cell-index" , &pdev->id , DT_REQUIRED , DT_U32 , -1},
{"qcom,i2c-src-freq", &pdata->src_clk_rate, DT_SUGGESTED, DT_U32, 0},
+ {"qcom,master-id" , &pdata->master_id , DT_SUGGESTED, DT_U32, 0},
{"qcom,scl-gpio" , gpios , DT_OPTIONAL , DT_GPIO, -1},
{"qcom,sda-gpio" , gpios + 1 , DT_OPTIONAL , DT_GPIO, -1},
+ {"qcom,active-only" , &pdata->active_only , DT_OPTIONAL , DT_BOOL, 0},
{NULL , NULL , 0 , 0 , 0},
};
for (itr = map; itr->dt_name ; ++itr) {
- if (itr->type == DT_GPIO) {
+ switch (itr->type) {
+ case DT_GPIO:
ret = of_get_named_gpio(node, itr->dt_name, 0);
if (ret >= 0) {
- *itr->ptr_data = ret;
+ *((int *) itr->ptr_data) = ret;
ret = 0;
}
- } else {
+ break;
+ case DT_U32:
ret = of_property_read_u32(node, itr->dt_name,
- itr->ptr_data);
+ (u32 *) itr->ptr_data);
+ break;
+ case DT_BOOL:
+ *((bool *) itr->ptr_data) =
+ of_property_read_bool(node, itr->dt_name);
+ ret = 0;
+ break;
+ default:
+ dev_err(&pdev->dev, "%d is an unknown DT entry type\n",
+ itr->type);
+ ret = -EBADE;
}
dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
- ret, itr->dt_name, *itr->ptr_data);
+ ret, itr->dt_name, *((int *)itr->ptr_data));
if (ret) {
- *itr->ptr_data = itr->default_val;
+ *((int *)itr->ptr_data) = itr->default_val;
if (itr->status < DT_OPTIONAL) {
dev_err(&pdev->dev, "Missing '%s' DT entry\n",
@@ -1326,6 +1510,14 @@
dev->clk_ctl = 0;
dev->pos = 0;
+ ret = i2c_qup_clk_path_init(pdev, dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to init clock path-voting data structs. err:%d", ret);
+ /* disable i2c_qup_clk_path_xxx() functionality */
+ dev->pdata->master_id = 0;
+ }
+
if (dev->pdata->src_clk_rate <= 0) {
dev_info(&pdev->dev,
"No src_clk_rate specified in platfrom data\n");
@@ -1443,6 +1635,7 @@
err_reset_failed:
clk_disable_unprepare(dev->clk);
clk_disable_unprepare(dev->pclk);
+ i2c_qup_clk_path_teardown(dev);
err_gsbi_failed:
iounmap(dev->base);
err_ioremap_failed:
@@ -1488,6 +1681,11 @@
clk_put(dev->pclk);
}
clk_put(dev->clk);
+
+ if (dev->pdata->active_only)
+ i2c_qup_clk_path_unvote(dev);
+ i2c_qup_clk_path_teardown(dev);
+
if (dev->gsbi)
iounmap(dev->gsbi);
iounmap(dev->base);
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ed53c41..ba94178 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -2567,7 +2567,7 @@
if (rmi4_data->board->i2c_pull_up) {
retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
- RMI4_I2C_LOAD_UA);
+ RMI4_I2C_LPM_LOAD_UA);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
"Regulator vcc_i2c set_opt failed rc=%d\n",
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 06f4a0f..eadbd64 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -32,6 +32,7 @@
#include <mach/msm_iommu_priv.h>
#include <mach/iommu.h>
#include <mach/msm_smem.h>
+#include <mach/msm_bus.h>
#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
@@ -135,6 +136,20 @@
return msm_iommu_remote_lock.lock;
}
+static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
+{
+ int ret = 0;
+
+ if (drvdata->bus_client) {
+ ret = msm_bus_scale_client_update_request(drvdata->bus_client,
+ vote);
+ if (ret)
+ pr_err("%s: Failed to vote for bus: %d\n", __func__,
+ vote);
+ }
+ return ret;
+}
+
static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
{
int ret;
@@ -202,6 +217,7 @@
struct iommu_access_ops iommu_access_ops_v0 = {
.iommu_power_on = __enable_regulators,
.iommu_power_off = __disable_regulators,
+ .iommu_bus_vote = apply_bus_vote,
.iommu_clk_on = __enable_clocks,
.iommu_clk_off = __disable_clocks,
.iommu_lock_initialize = _iommu_lock_initialize,
@@ -506,6 +522,11 @@
goto unlock;
}
+ ret = apply_bus_vote(iommu_drvdata, 1);
+
+ if (ret)
+ goto unlock;
+
ret = __enable_clocks(iommu_drvdata);
if (ret)
goto unlock;
@@ -572,6 +593,9 @@
msm_iommu_remote_spin_unlock();
__disable_clocks(iommu_drvdata);
+
+ apply_bus_vote(iommu_drvdata, 0);
+
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
unlock:
@@ -1257,7 +1281,7 @@
return 0;
}
-static void print_ctx_regs(void __iomem *base, int ctx)
+static void __print_ctx_regs(void __iomem *base, int ctx)
{
unsigned int fsr = GET_FSR(base, ctx);
pr_err("FAR = %08x PAR = %08x\n",
@@ -1323,7 +1347,7 @@
pr_err("name = %s\n", drvdata->name);
pr_err("context = %s (%d)\n", ctx_drvdata->name, num);
pr_err("Interesting registers:\n");
- print_ctx_regs(base, num);
+ __print_ctx_regs(base, num);
}
SET_FSR(base, num, fsr);
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 8e68beb..5ee8794 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -32,6 +32,7 @@
#include <mach/iommu.h>
#include <mach/msm_iommu_priv.h>
#include <mach/iommu_perfmon.h>
+#include <mach/msm_bus.h>
#include "msm_iommu_pagetable.h"
/* bitmap of the page sizes currently supported */
@@ -62,6 +63,20 @@
regulator_disable(drvdata->gdsc);
}
+static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
+{
+ int ret = 0;
+
+ if (drvdata->bus_client) {
+ ret = msm_bus_scale_client_update_request(drvdata->bus_client,
+ vote);
+ if (ret)
+ pr_err("%s: Failed to vote for bus: %d\n", __func__,
+ vote);
+ }
+ return ret;
+}
+
static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
{
int ret;
@@ -116,6 +131,7 @@
struct iommu_access_ops iommu_access_ops_v1 = {
.iommu_power_on = __enable_regulators,
.iommu_power_off = __disable_regulators,
+ .iommu_bus_vote = apply_bus_vote,
.iommu_clk_on = __enable_clocks,
.iommu_clk_off = __disable_clocks,
.iommu_lock_acquire = _iommu_lock_acquire,
@@ -513,6 +529,10 @@
if (ret)
goto fail;
+ ret = apply_bus_vote(iommu_drvdata, 1);
+ if (ret)
+ goto fail;
+
ret = __enable_clocks(iommu_drvdata);
if (ret) {
__disable_regulators(iommu_drvdata);
@@ -602,6 +622,8 @@
__disable_clocks(iommu_drvdata);
+ apply_bus_vote(iommu_drvdata, 0);
+
__disable_regulators(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
@@ -761,10 +783,12 @@
return 0;
}
-static void print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+void print_ctx_regs(struct msm_iommu_context_regs *regs)
{
+ uint32_t fsr = regs->fsr;
+
pr_err("FAR = %08x PAR = %08x\n",
- GET_FAR(base, ctx), GET_PAR(base, ctx));
+ regs->far, regs->par);
pr_err("FSR = %08x [%s%s%s%s%s%s%s%s%s]\n", fsr,
(fsr & 0x02) ? "TF " : "",
(fsr & 0x04) ? "AFF " : "",
@@ -777,13 +801,31 @@
(fsr & 0x80000000) ? "MULTI " : "");
pr_err("FSYNR0 = %08x FSYNR1 = %08x\n",
- GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
+ regs->fsynr0, regs->fsynr1);
pr_err("TTBR0 = %08x TTBR1 = %08x\n",
- GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
+ regs->ttbr0, regs->ttbr1);
pr_err("SCTLR = %08x ACTLR = %08x\n",
- GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
+ regs->sctlr, regs->actlr);
pr_err("PRRR = %08x NMRR = %08x\n",
- GET_PRRR(base, ctx), GET_NMRR(base, ctx));
+ regs->prrr, regs->nmrr);
+}
+
+static void __print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+{
+ struct msm_iommu_context_regs regs = {
+ .far = GET_FAR(base, ctx),
+ .par = GET_PAR(base, ctx),
+ .fsr = fsr,
+ .fsynr0 = GET_FSYNR0(base, ctx),
+ .fsynr1 = GET_FSYNR1(base, ctx),
+ .ttbr0 = GET_TTBR0(base, ctx),
+ .ttbr1 = GET_TTBR1(base, ctx),
+ .sctlr = GET_SCTLR(base, ctx),
+ .actlr = GET_ACTLR(base, ctx),
+ .prrr = GET_PRRR(base, ctx),
+ .nmrr = GET_NMRR(base, ctx),
+ };
+ print_ctx_regs(®s);
}
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
@@ -839,7 +881,7 @@
pr_err("context = %s (%d)\n", ctx_drvdata->name,
ctx_drvdata->num);
pr_err("Interesting registers:\n");
- print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
+ __print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
}
SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 059216e..4ee65d8 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -30,10 +30,13 @@
#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
+#include <mach/msm_bus.h>
static DEFINE_MUTEX(iommu_list_lock);
static LIST_HEAD(iommu_list);
+static struct of_device_id msm_iommu_v0_ctx_match_table[];
+
void msm_iommu_add_drv(struct msm_iommu_drvdata *drv)
{
mutex_lock(&iommu_list_lock);
@@ -77,10 +80,13 @@
}
mutex_unlock(&iommu_list_lock);
- if (!dev || !dev_get_drvdata(dev))
- pr_err("Could not find context <%s>\n", ctx_name);
put_device(dev);
+ if (!dev || !dev_get_drvdata(dev)) {
+ pr_debug("Could not find context <%s>\n", ctx_name);
+ dev = ERR_PTR(-EPROBE_DEFER);
+ }
+
return dev;
}
EXPORT_SYMBOL(msm_iommu_get_ctx);
@@ -128,74 +134,24 @@
mb();
}
-static int msm_iommu_parse_dt(struct platform_device *pdev,
- struct msm_iommu_drvdata *drvdata,
- int *needs_alt_core_clk)
-{
-#ifdef CONFIG_OF_DEVICE
- struct device_node *child;
- struct resource *r;
- u32 glb_offset = 0;
- int ret;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- pr_err("%s: Missing property reg\n", __func__);
- return -EINVAL;
- }
- drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (!drvdata->base) {
- pr_err("%s: Unable to ioremap %pr\n", __func__, r);
- return -ENOMEM;
- }
- drvdata->glb_base = drvdata->base;
-
- if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
- &glb_offset)) {
- drvdata->glb_base += glb_offset;
- } else {
- pr_err("%s: Missing property qcom,glb-offset\n", __func__);
- return -EINVAL;
- }
-
- for_each_child_of_node(pdev->dev.of_node, child) {
- drvdata->ncb++;
- if (!of_platform_device_create(child, NULL, &pdev->dev))
- pr_err("Failed to create %s device\n", child->name);
- }
-
- ret = of_property_read_string(pdev->dev.of_node, "label",
- &drvdata->name);
- if (ret) {
- pr_err("%s: Missing property label\n", __func__);
- return -EINVAL;
- }
-
- *needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
- "qcom,needs-alt-core-clk");
-
- drvdata->sec_id = -1;
- drvdata->ttbr_split = 0;
-#endif
- return 0;
-}
-
static int __get_clocks(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata,
int needs_alt_core_clk)
{
int ret = 0;
- drvdata->pclk = clk_get(&pdev->dev, "iface_clk");
+ drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(drvdata->pclk)) {
ret = PTR_ERR(drvdata->pclk);
drvdata->pclk = NULL;
- pr_err("Unable to get %s clock for %s IOMMU device\n",
- dev_name(&pdev->dev), drvdata->name);
+ if (ret != -EPROBE_DEFER) {
+ pr_err("Unable to get %s clock for %s IOMMU device\n",
+ dev_name(&pdev->dev), drvdata->name);
+ }
goto fail;
}
- drvdata->clk = clk_get(&pdev->dev, "core_clk");
+ drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
if (!IS_ERR(drvdata->clk)) {
if (clk_get_rate(drvdata->clk) == 0) {
@@ -208,8 +164,10 @@
if (needs_alt_core_clk) {
drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
- if (IS_ERR(drvdata->aclk))
- return PTR_ERR(drvdata->aclk);
+ if (IS_ERR(drvdata->aclk)) {
+ ret = PTR_ERR(drvdata->aclk);
+ goto fail;
+ }
}
if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
@@ -222,15 +180,127 @@
return ret;
}
-static void __put_clocks(struct msm_iommu_drvdata *drvdata)
+#ifdef CONFIG_OF_DEVICE
+
+static int __get_bus_vote_client(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
{
- if (drvdata->aclk)
- clk_put(drvdata->aclk);
- if (drvdata->clk)
- clk_put(drvdata->clk);
- clk_put(drvdata->pclk);
+ int ret = 0;
+ struct msm_bus_scale_pdata *bs_table;
+ const char *dummy;
+
+ /* Check whether bus scaling has been specified for this node */
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+ &dummy);
+ if (ret)
+ return 0;
+
+ bs_table = msm_bus_cl_get_pdata(pdev);
+
+ if (bs_table) {
+ drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+ if (IS_ERR(&drvdata->bus_client)) {
+ pr_err("%s(): Bus client register failed.\n", __func__);
+ ret = -EINVAL;
+ }
+ }
+ return ret;
}
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+ msm_bus_scale_unregister_client(drvdata->bus_client);
+ drvdata->bus_client = 0;
+}
+
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ struct device_node *child;
+ struct resource *r;
+ u32 glb_offset = 0;
+ int ret = 0;
+ int needs_alt_core_clk;
+
+ ret = __get_bus_vote_client(pdev, drvdata);
+
+ if (ret)
+ goto fail;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ pr_err("%s: Missing property reg\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+ drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!drvdata->base) {
+ pr_err("%s: Unable to ioremap %pr\n", __func__, r);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ drvdata->glb_base = drvdata->base;
+
+ if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
+ &glb_offset)) {
+ drvdata->glb_base += glb_offset;
+ } else {
+ pr_err("%s: Missing property qcom,glb-offset\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, child)
+ drvdata->ncb++;
+
+ ret = of_property_read_string(pdev->dev.of_node, "label",
+ &drvdata->name);
+ if (ret) {
+ pr_err("%s: Missing property label\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
+ "qcom,needs-alt-core-clk");
+
+ ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
+
+ if (ret)
+ goto fail;
+
+ drvdata->sec_id = -1;
+ drvdata->ttbr_split = 0;
+
+ ret = of_platform_populate(pdev->dev.of_node,
+ msm_iommu_v0_ctx_match_table,
+ NULL, &pdev->dev);
+ if (ret) {
+ pr_err("Failed to create iommu context device\n");
+ goto fail;
+ }
+
+ return ret;
+
+fail:
+ __put_bus_vote_client(drvdata);
+ return ret;
+}
+
+#else
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ return 0;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+
+}
+
+#endif
+
/*
* Do a basic check of the IOMMU by performing an ATS operation
* on context bank 0.
@@ -322,23 +392,27 @@
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
int ret;
- int needs_alt_core_clk = 0;
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
ret = -ENOMEM;
- goto fail;
+ goto fail_mem;
}
if (pdev->dev.of_node) {
- ret = msm_iommu_parse_dt(pdev, drvdata, &needs_alt_core_clk);
+ ret = msm_iommu_parse_dt(pdev, drvdata);
if (ret)
goto fail;
} else if (pdev->dev.platform_data) {
struct resource *r, *r2;
resource_size_t len;
+ ret = __get_clocks(pdev, drvdata, 0);
+
+ if (ret)
+ goto fail;
+
r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"physbase");
@@ -349,7 +423,8 @@
len = resource_size(r);
- r2 = request_mem_region(r->start, len, r->name);
+ r2 = devm_request_mem_region(&pdev->dev, r->start,
+ len, r->name);
if (!r2) {
pr_err("Could not request memory region: %pr\n", r);
ret = -EBUSY;
@@ -379,11 +454,6 @@
drvdata->dev = &pdev->dev;
- ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
-
- if (ret)
- goto fail;
-
iommu_access_ops_v0.iommu_clk_on(drvdata);
msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
@@ -392,14 +462,14 @@
if (ret)
goto fail_clk;
+ iommu_access_ops_v0.iommu_clk_off(drvdata);
+
pr_info("device %s mapped at %p, with %d ctx banks\n",
drvdata->name, drvdata->base, drvdata->ncb);
msm_iommu_add_drv(drvdata);
platform_set_drvdata(pdev, drvdata);
- iommu_access_ops_v0.iommu_clk_off(drvdata);
-
pmon_info = msm_iommu_pm_alloc(&pdev->dev);
if (pmon_info != NULL) {
ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
@@ -428,8 +498,9 @@
fail_clk:
iommu_access_ops_v0.iommu_clk_off(drvdata);
- __put_clocks(drvdata);
fail:
+ __put_bus_vote_client(drvdata);
+fail_mem:
return ret;
}
@@ -437,12 +508,13 @@
{
struct msm_iommu_drvdata *drv = NULL;
+ msm_iommu_pm_iommu_unregister(&pdev->dev);
+ msm_iommu_pm_free(&pdev->dev);
+
drv = platform_get_drvdata(pdev);
if (drv) {
+ __put_bus_vote_client(drv);
msm_iommu_remove_drv(drv);
- if (drv->clk)
- clk_put(drv->clk);
- clk_put(drv->pclk);
platform_set_drvdata(pdev, NULL);
}
return 0;
@@ -458,26 +530,28 @@
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
- ret = request_threaded_irq(irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
msm_iommu_fault_handler,
IRQF_ONESHOT | IRQF_SHARED,
"msm_iommu_nonsecure_irq", ctx_drvdata);
if (ret) {
pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
- return ret;
+ goto out;
}
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
pr_err("Could not find reg property for context bank\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
if (ret) {
pr_err("of_address_to_resource failed\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/* Calculate the context bank number using the base addresses. CB0
@@ -488,29 +562,34 @@
if (of_property_read_string(pdev->dev.of_node, "label",
&ctx_drvdata->name)) {
pr_err("Could not find label property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-mids",
&nmid_array_size)) {
pr_err("Could not find iommu-ctx-mids property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (nmid_array_size >= sizeof(ctx_drvdata->sids)) {
pr_err("Too many mids defined - array size: %u, mids size: %u\n",
nmid_array_size, sizeof(ctx_drvdata->sids));
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
nmid = nmid_array_size / sizeof(*ctx_drvdata->sids);
if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-mids",
ctx_drvdata->sids, nmid)) {
pr_err("Could not find iommu-ctx-mids property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ctx_drvdata->nsid = nmid;
- return 0;
+out:
+ return ret;
}
static void __program_m2v_tables(struct msm_iommu_drvdata *drvdata,
@@ -560,7 +639,7 @@
drvdata = dev_get_drvdata(pdev->dev.parent);
if (!drvdata) {
- ret = -ENODEV;
+ ret = -EPROBE_DEFER;
goto fail;
}
@@ -578,8 +657,10 @@
if (pdev->dev.of_node) {
ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
- if (ret)
+ if (ret) {
+ platform_set_drvdata(pdev, NULL);
goto fail;
+ }
} else if (pdev->dev.platform_data) {
struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
@@ -601,7 +682,8 @@
goto fail;
}
- ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ msm_iommu_fault_handler,
IRQF_ONESHOT | IRQF_SHARED,
"msm_iommu_nonsecure_irq", ctx_drvdata);
@@ -647,15 +729,15 @@
.remove = __devexit_p(msm_iommu_remove),
};
-static struct of_device_id msm_iommu_ctx_match_table[] = {
- { .name = "qcom,iommu-ctx", },
+static struct of_device_id msm_iommu_v0_ctx_match_table[] = {
+ { .compatible = "qcom,msm-smmu-v0-ctx", },
{}
};
static struct platform_driver msm_iommu_ctx_driver = {
.driver = {
.name = "msm_iommu_ctx",
- .of_match_table = msm_iommu_ctx_match_table,
+ .of_match_table = msm_iommu_v0_ctx_match_table,
},
.probe = msm_iommu_ctx_probe,
.remove = __devexit_p(msm_iommu_ctx_remove),
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 418a086..c0e05f4 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -28,6 +28,9 @@
#include <mach/iommu_hw-v1.h>
#include <mach/iommu.h>
#include <mach/iommu_perfmon.h>
+#include <mach/msm_bus.h>
+
+static struct of_device_id msm_iommu_v1_ctx_match_table[];
static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
@@ -84,6 +87,36 @@
return 0;
}
+static int __get_bus_vote_client(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ int ret = 0;
+ struct msm_bus_scale_pdata *bs_table;
+ const char *dummy;
+
+ /* Check whether bus scaling has been specified for this node */
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+ &dummy);
+ if (ret)
+ return 0;
+
+ bs_table = msm_bus_cl_get_pdata(pdev);
+
+ if (bs_table) {
+ drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+ if (IS_ERR(&drvdata->bus_client)) {
+ pr_err("%s(): Bus client register failed.\n", __func__);
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+ msm_bus_scale_unregister_client(drvdata->bus_client);
+}
+
static int msm_iommu_parse_dt(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
{
@@ -92,17 +125,18 @@
struct resource *r;
drvdata->dev = &pdev->dev;
- msm_iommu_add_drv(drvdata);
+
+ ret = __get_bus_vote_client(pdev, drvdata);
+
+ if (ret)
+ goto fail;
ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
if (ret)
goto fail;
- for_each_child_of_node(pdev->dev.of_node, child) {
+ for_each_child_of_node(pdev->dev.of_node, child)
drvdata->ncb++;
- if (!of_platform_device_create(child, NULL, &pdev->dev))
- pr_err("Failed to create %s device\n", child->name);
- }
drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
GFP_KERNEL);
@@ -137,8 +171,15 @@
drvdata->halt_enabled = of_property_read_bool(pdev->dev.of_node,
"qcom,iommu-enable-halt");
- return 0;
+ ret = of_platform_populate(pdev->dev.of_node,
+ msm_iommu_v1_ctx_match_table,
+ NULL, &pdev->dev);
+ if (ret)
+ pr_err("Failed to create iommu context device\n");
+
+ msm_iommu_add_drv(drvdata);
fail:
+ __put_bus_vote_client(drvdata);
return ret;
}
@@ -224,7 +265,7 @@
drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(drvdata->gdsc))
- return -EINVAL;
+ return PTR_ERR(drvdata->gdsc);
drvdata->alt_gdsc = devm_regulator_get(&pdev->dev, "qcom,alt-vdd");
if (IS_ERR(drvdata->alt_gdsc))
@@ -301,10 +342,8 @@
drv = platform_get_drvdata(pdev);
if (drv) {
+ __put_bus_vote_client(drv);
msm_iommu_remove_drv(drv);
- if (drv->clk)
- clk_put(drv->clk);
- clk_put(drv->pclk);
platform_set_drvdata(pdev, NULL);
}
return 0;
@@ -314,7 +353,7 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata)
{
struct resource *r, rp;
- int irq, ret;
+ int irq = 0, ret = 0;
u32 nsid;
ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
@@ -323,25 +362,27 @@
if (!ctx_drvdata->secure_context) {
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
- ret = request_threaded_irq(irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
msm_iommu_fault_handler_v2,
IRQF_ONESHOT | IRQF_SHARED,
"msm_iommu_nonsecure_irq", pdev);
if (ret) {
pr_err("Request IRQ %d failed with ret=%d\n",
irq, ret);
- return ret;
+ goto out;
}
}
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r)
- return -EINVAL;
+ if (!r) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
if (ret)
- return -EINVAL;
+ goto out;
/* Calculate the context bank number using the base addresses. The
* first 8 pages belong to the global address space which is followed
@@ -354,21 +395,26 @@
&ctx_drvdata->name))
ctx_drvdata->name = dev_name(&pdev->dev);
- if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid))
- return -EINVAL;
-
- if (nsid >= sizeof(ctx_drvdata->sids))
- return -EINVAL;
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (nsid >= sizeof(ctx_drvdata->sids)) {
+ ret = -EINVAL;
+ goto out;
+ }
if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
ctx_drvdata->sids,
nsid / sizeof(*ctx_drvdata->sids))) {
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ctx_drvdata->nsid = nsid;
ctx_drvdata->asid = -1;
- return 0;
+out:
+ return ret;
}
static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
@@ -386,12 +432,14 @@
ctx_drvdata->pdev = pdev;
INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
- platform_set_drvdata(pdev, ctx_drvdata);
ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
- if (!ret)
+ if (!ret) {
+ platform_set_drvdata(pdev, ctx_drvdata);
+
dev_info(&pdev->dev, "context %s using bank %d\n",
ctx_drvdata->name, ctx_drvdata->num);
+ }
return ret;
}
@@ -416,15 +464,15 @@
.remove = __devexit_p(msm_iommu_remove),
};
-static struct of_device_id msm_iommu_ctx_match_table[] = {
- { .name = "qcom,iommu-ctx", },
+static struct of_device_id msm_iommu_v1_ctx_match_table[] = {
+ { .compatible = "qcom,msm-smmu-v1-ctx", },
{}
};
static struct platform_driver msm_iommu_ctx_driver = {
.driver = {
.name = "msm_iommu_ctx_v1",
- .of_match_table = msm_iommu_ctx_match_table,
+ .of_match_table = msm_iommu_v1_ctx_match_table,
},
.probe = msm_iommu_ctx_probe,
.remove = __devexit_p(msm_iommu_ctx_remove),
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index a11d794..958c6ca 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -257,6 +257,7 @@
dev_get_drvdata(iommu->iommu_dev);
iommu->ops->iommu_power_on(iommu_drvdata);
+ iommu->ops->iommu_bus_vote(iommu_drvdata, 1);
iommu->ops->iommu_clk_on(iommu_drvdata);
/* Reset counters in HW */
@@ -311,6 +312,7 @@
iommu->ops->iommu_lock_release();
iommu->ops->iommu_clk_off(iommu_drvdata);
+ iommu->ops->iommu_bus_vote(iommu_drvdata, 0);
iommu->ops->iommu_power_off(iommu_drvdata);
pr_info("%s: TLB performance monitoring turned OFF\n",
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 0233e18..9101a3d 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -166,7 +166,8 @@
#define LED_MPP_EN_CTRL(base) (base + 0x46)
#define LED_MPP_SINK_CTRL(base) (base + 0x4C)
-#define LED_MPP_CURRENT_DEFAULT 10
+#define LED_MPP_CURRENT_DEFAULT 5
+#define LED_MPP_CURRENT_PER_SETTING 5
#define LED_MPP_SOURCE_SEL_DEFAULT LED_MPP_MODE_ENABLE
#define LED_MPP_SINK_MASK 0x07
@@ -258,6 +259,7 @@
enum led_mode {
PWM_MODE = 0,
LPG_MODE,
+ MANUAL_MODE,
};
static u8 wled_debug_regs[] = {
@@ -290,6 +292,24 @@
};
/**
+ * pwm_config_data - pwm configuration data
+ * @lut_params - lut parameters to be used by pwm driver
+ * @pwm_device - pwm device
+ * @pwm_channel - pwm channel to be configured for led
+ * @pwm_period_us - period for pwm, in us
+ * @mode - mode the led operates in
+ */
+struct pwm_config_data {
+ struct lut_params lut_params;
+ struct pwm_device *pwm_dev;
+ int pwm_channel;
+ u32 pwm_period_us;
+ struct pwm_duty_cycles *duty_cycles;
+ u8 mode;
+ u8 enable;
+};
+
+/**
* wled_config_data - wled configuration data
* @num_strings - number of wled strings supported
* @ovp_val - over voltage protection threshold
@@ -314,12 +334,18 @@
/**
* mpp_config_data - mpp configuration data
+ * @pwm_cfg - device pwm configuration
* @current_setting - current setting, 5ma-40ma in 5ma increments
+ * @source_sel - source selection
+ * @mode_ctrl - mode control
+ * @pwm_mode - pwm mode in use
*/
struct mpp_config_data {
+ struct pwm_config_data *pwm_cfg;
u8 current_setting;
u8 source_sel;
u8 mode_ctrl;
+ u8 pwm_mode;
};
/**
@@ -354,38 +380,25 @@
/**
* kpdbl_config_data - kpdbl configuration data
- * @pwm_device - pwm device
- * @pwm_channel - pwm channel to be configured for led
- * @pwm_period_us - period for pwm, in us
+ * @pwm_cfg - device pwm configuration
* @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
* @row_scan_en - enable row scan
* @row_scan_val - map to enable needed rows
*/
struct kpdbl_config_data {
- struct pwm_device *pwm_dev;
- int pwm_channel;
- u32 pwm_period_us;
+ struct pwm_config_data *pwm_cfg;
u32 row_src_sel_val;
u32 row_scan_en;
u32 row_scan_val;
- u8 mode;
};
/**
* rgb_config_data - rgb configuration data
- * @lut_params - lut parameters to be used by pwm driver
- * @pwm_device - pwm device
- * @pwm_channel - pwm channel to be configured for led
- * @pwm_period_us - period for pwm, in us
- * @mode - mode the led operates in
+ * @pwm_cfg - device pwm configuration
+ * @enable - bits to enable led
*/
struct rgb_config_data {
- struct lut_params lut_params;
- struct pwm_device *pwm_dev;
- int pwm_channel;
- u32 pwm_period_us;
- struct pwm_duty_cycles *duty_cycles;
- u8 mode;
+ struct pwm_config_data *pwm_cfg;
u8 enable;
};
@@ -542,24 +555,33 @@
static int qpnp_mpp_set(struct qpnp_led_data *led)
{
int rc, val;
+ int duty_us;
if (led->cdev.brightness) {
- val = (led->cdev.brightness * LED_MPP_SINK_MASK) / LED_FULL;
- rc = qpnp_led_masked_write(led,
- LED_MPP_SINK_CTRL(led->base),
- LED_MPP_SINK_MASK, val);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Failed to write led enable reg\n");
- return rc;
+ if (led->mpp_cfg->pwm_mode == PWM_MODE) {
+ pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
+ duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
+ led->cdev.brightness) / LED_FULL;
+ /*config pwm for brightness scaling*/
+ rc = pwm_config(led->mpp_cfg->pwm_cfg->pwm_dev,
+ duty_us,
+ led->mpp_cfg->pwm_cfg->pwm_period_us);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev, "Failed to " \
+ "configure pwm for new values\n");
+ return rc;
+ }
}
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+ pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
+
val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
(led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
rc = qpnp_led_masked_write(led,
- LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
- val);
+ LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
+ val);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Failed to write led mode reg\n");
@@ -569,13 +591,15 @@
rc = qpnp_led_masked_write(led,
LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
LED_MPP_EN_ENABLE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Failed to write led enable " \
- "reg\n");
- return rc;
- }
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to write led enable " \
+ "reg\n");
+ return rc;
+ }
} else {
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+ pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
rc = qpnp_led_masked_write(led,
LED_MPP_MODE_CTRL(led->base),
LED_MPP_MODE_MASK,
@@ -831,21 +855,21 @@
if (led->cdev.brightness) {
rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
- duty_us = (led->kpdbl_cfg->pwm_period_us *
+ duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / KPDBL_MAX_LEVEL;
- rc = pwm_config(led->kpdbl_cfg->pwm_dev, duty_us,
- led->kpdbl_cfg->pwm_period_us);
+ rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, duty_us,
+ led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev, "pwm config failed\n");
return rc;
}
- rc = pwm_enable(led->kpdbl_cfg->pwm_dev);
+ rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
if (rc < 0) {
dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
return rc;
}
} else {
- pwm_disable(led->kpdbl_cfg->pwm_dev);
+ pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
if (rc) {
@@ -866,11 +890,11 @@
int rc;
if (led->cdev.brightness) {
- if (led->rgb_cfg->mode == PWM_MODE) {
- duty_us = (led->rgb_cfg->pwm_period_us *
+ if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
+ duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
- rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
- led->rgb_cfg->pwm_period_us);
+ rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
+ led->rgb_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"pwm config failed\n");
@@ -885,13 +909,14 @@
"Failed to write led enable reg\n");
return rc;
}
- rc = pwm_enable(led->rgb_cfg->pwm_dev);
+
+ rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
if (rc < 0) {
dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
return rc;
}
} else {
- pwm_disable(led->rgb_cfg->pwm_dev);
+ pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
rc = qpnp_led_masked_write(led,
RGB_LED_EN_CTL(led->base),
led->rgb_cfg->enable, RGB_LED_DISABLE);
@@ -1299,6 +1324,63 @@
return 0;
}
+static int __devinit qpnp_pwm_init(struct pwm_config_data *pwm_cfg,
+ struct spmi_device *spmi_dev,
+ const char *name)
+{
+ int rc, start_idx, idx_len;
+
+ if (pwm_cfg->pwm_channel != -1) {
+ pwm_cfg->pwm_dev =
+ pwm_request(pwm_cfg->pwm_channel, name);
+
+ if (IS_ERR_OR_NULL(pwm_cfg->pwm_dev)) {
+ dev_err(&spmi_dev->dev,
+ "could not acquire PWM Channel %d, " \
+ "error %ld\n",
+ pwm_cfg->pwm_channel,
+ PTR_ERR(pwm_cfg->pwm_dev));
+ pwm_cfg->pwm_dev = NULL;
+ return -ENODEV;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE) {
+ start_idx =
+ pwm_cfg->duty_cycles->start_idx;
+ idx_len =
+ pwm_cfg->duty_cycles->num_duty_pcts;
+
+ if (idx_len >= PWM_LUT_MAX_SIZE &&
+ start_idx) {
+ dev_err(&spmi_dev->dev,
+ "Wrong LUT size or index\n");
+ return -EINVAL;
+ }
+ if ((start_idx + idx_len) >
+ PWM_LUT_MAX_SIZE) {
+ dev_err(&spmi_dev->dev,
+ "Exceed LUT limit\n");
+ return -EINVAL;
+ }
+ rc = pwm_lut_config(pwm_cfg->pwm_dev,
+ PM_PWM_PERIOD_MIN, /* ignored by hardware */
+ pwm_cfg->duty_cycles->duty_pcts,
+ pwm_cfg->lut_params);
+ if (rc < 0) {
+ dev_err(&spmi_dev->dev, "Failed to " \
+ "configure pwm LUT\n");
+ return rc;
+ }
+ }
+ } else {
+ dev_err(&spmi_dev->dev,
+ "Invalid PWM channel\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int __devinit qpnp_kpdbl_init(struct qpnp_led_data *led)
{
int rc;
@@ -1348,24 +1430,12 @@
return rc;
}
- if (led->kpdbl_cfg->pwm_channel != -1) {
- led->kpdbl_cfg->pwm_dev =
- pwm_request(led->kpdbl_cfg->pwm_channel,
- led->cdev.name);
-
- if (IS_ERR_OR_NULL(led->kpdbl_cfg->pwm_dev)) {
- dev_err(&led->spmi_dev->dev,
- "could not acquire PWM Channel %d, " \
- "error %ld\n",
- led->kpdbl_cfg->pwm_channel,
- PTR_ERR(led->kpdbl_cfg->pwm_dev));
- led->kpdbl_cfg->pwm_dev = NULL;
- return -ENODEV;
- }
- } else {
+ rc = qpnp_pwm_init(led->kpdbl_cfg->pwm_cfg, led->spmi_dev,
+ led->cdev.name);
+ if (rc) {
dev_err(&led->spmi_dev->dev,
- "Invalid PWM channel\n");
- return -EINVAL;
+ "Failed to initialize pwm\n");
+ return rc;
}
/* dump kpdbl registers */
@@ -1376,7 +1446,7 @@
static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
{
- int rc, start_idx, idx_len;
+ int rc;
rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
@@ -1386,55 +1456,13 @@
return rc;
}
- if (led->rgb_cfg->pwm_channel != -1) {
- led->rgb_cfg->pwm_dev =
- pwm_request(led->rgb_cfg->pwm_channel,
- led->cdev.name);
-
- if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
- dev_err(&led->spmi_dev->dev,
- "could not acquire PWM Channel %d, " \
- "error %ld\n",
- led->rgb_cfg->pwm_channel,
- PTR_ERR(led->rgb_cfg->pwm_dev));
- led->rgb_cfg->pwm_dev = NULL;
- return -ENODEV;
- }
-
- if (led->rgb_cfg->mode == LPG_MODE) {
- start_idx =
- led->rgb_cfg->duty_cycles->start_idx;
- idx_len =
- led->rgb_cfg->duty_cycles->num_duty_pcts;
-
- if (idx_len >= PWM_LUT_MAX_SIZE &&
- start_idx) {
- dev_err(&led->spmi_dev->dev,
- "Wrong LUT size or index\n");
- return -EINVAL;
- }
- if ((start_idx + idx_len) >
- PWM_LUT_MAX_SIZE) {
- dev_err(&led->spmi_dev->dev,
- "Exceed LUT limit\n");
- return -EINVAL;
- }
- rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
- PM_PWM_PERIOD_MIN, /* ignored by hardware */
- led->rgb_cfg->duty_cycles->duty_pcts,
- led->rgb_cfg->lut_params);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev, "Failed to " \
- "configure pwm LUT\n");
- return rc;
- }
- }
- } else {
+ rc = qpnp_pwm_init(led->rgb_cfg->pwm_cfg, led->spmi_dev,
+ led->cdev.name);
+ if (rc) {
dev_err(&led->spmi_dev->dev,
- "Invalid PWM channel\n");
- return -EINVAL;
+ "Failed to initialize pwm\n");
+ return rc;
}
-
/* Initialize led for use in auto trickle charging mode */
rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
led->rgb_cfg->enable, led->rgb_cfg->enable);
@@ -1442,6 +1470,36 @@
return 0;
}
+static int __devinit qpnp_mpp_init(struct qpnp_led_data *led)
+{
+ int rc, val;
+
+ val = (led->mpp_cfg->current_setting / LED_MPP_CURRENT_PER_SETTING) - 1;
+
+ if (val < 0)
+ val = 0;
+
+ rc = qpnp_led_masked_write(led, LED_MPP_SINK_CTRL(led->base),
+ LED_MPP_SINK_MASK, val);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to write led enable reg\n");
+ return rc;
+ }
+
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
+ rc = qpnp_pwm_init(led->mpp_cfg->pwm_cfg, led->spmi_dev,
+ led->cdev.name);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to initialize pwm\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
{
int rc = 0;
@@ -1469,6 +1527,10 @@
"RGB initialize failed(%d)\n", rc);
break;
case QPNP_ID_LED_MPP:
+ rc = qpnp_mpp_init(led);
+ if (rc)
+ dev_err(&led->spmi_dev->dev,
+ "MPP initialize failed(%d)\n", rc);
break;
case QPNP_ID_KPDBL:
rc = qpnp_kpdbl_init(led);
@@ -1631,7 +1693,7 @@
if (!rc)
led->flash_cfg->headroom = (u8) val;
else if (rc == -EINVAL)
- led->flash_cfg->headroom = HEADROOM_300mV;
+ led->flash_cfg->headroom = HEADROOM_500mV;
else
return rc;
@@ -1656,7 +1718,7 @@
if (!rc)
led->flash_cfg->startup_dly = (u8) val;
else if (rc == -EINVAL)
- led->flash_cfg->startup_dly = DELAY_32us;
+ led->flash_cfg->startup_dly = DELAY_128us;
else
return rc;
@@ -1669,11 +1731,138 @@
return 0;
}
+static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
+ struct spmi_device *spmi_dev,
+ struct device_node *node)
+{
+ struct property *prop;
+ int rc, i;
+ u32 val;
+ u8 *temp_cfg;
+
+ rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
+ if (!rc)
+ pwm_cfg->pwm_channel = val;
+ else
+ return rc;
+
+ if (pwm_cfg->mode == PWM_MODE) {
+ rc = of_property_read_u32(node, "qcom,pwm-us", &val);
+ if (!rc)
+ pwm_cfg->pwm_period_us = val;
+ else
+ return rc;
+ }
+
+ if (pwm_cfg->mode == LPG_MODE) {
+ pwm_cfg->duty_cycles =
+ devm_kzalloc(&spmi_dev->dev,
+ sizeof(struct pwm_duty_cycles), GFP_KERNEL);
+ if (!pwm_cfg->duty_cycles) {
+ dev_err(&spmi_dev->dev,
+ "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ prop = of_find_property(node, "qcom,duty-pcts",
+ &pwm_cfg->duty_cycles->num_duty_pcts);
+ if (!prop) {
+ dev_err(&spmi_dev->dev, "Looking up property " \
+ "node qcom,duty-pcts failed\n");
+ return -ENODEV;
+ } else if (!pwm_cfg->duty_cycles->num_duty_pcts) {
+ dev_err(&spmi_dev->dev, "Invalid length of " \
+ "duty pcts\n");
+ return -EINVAL;
+ }
+
+ pwm_cfg->duty_cycles->duty_pcts =
+ devm_kzalloc(&spmi_dev->dev,
+ sizeof(int) * pwm_cfg->duty_cycles->num_duty_pcts,
+ GFP_KERNEL);
+ if (!pwm_cfg->duty_cycles->duty_pcts) {
+ dev_err(&spmi_dev->dev,
+ "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ temp_cfg = devm_kzalloc(&spmi_dev->dev,
+ pwm_cfg->duty_cycles->num_duty_pcts *
+ sizeof(u8), GFP_KERNEL);
+ if (!temp_cfg) {
+ dev_err(&spmi_dev->dev, "Failed to allocate " \
+ "memory for duty pcts\n");
+ return -ENOMEM;
+ }
+
+ memcpy(temp_cfg, prop->value,
+ pwm_cfg->duty_cycles->num_duty_pcts);
+
+ for (i = 0; i < pwm_cfg->duty_cycles->num_duty_pcts; i++)
+ pwm_cfg->duty_cycles->duty_pcts[i] =
+ (int) temp_cfg[i];
+
+ rc = of_property_read_u32(node, "qcom,start-idx", &val);
+ if (!rc) {
+ pwm_cfg->lut_params.start_idx = val;
+ pwm_cfg->duty_cycles->start_idx = val;
+ } else
+ return rc;
+
+ pwm_cfg->lut_params.lut_pause_hi = 0;
+ rc = of_property_read_u32(node, "qcom,pause-hi", &val);
+ if (!rc)
+ pwm_cfg->lut_params.lut_pause_hi = val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ pwm_cfg->lut_params.lut_pause_lo = 0;
+ rc = of_property_read_u32(node, "qcom,pause-lo", &val);
+ if (!rc)
+ pwm_cfg->lut_params.lut_pause_lo = val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ pwm_cfg->lut_params.ramp_step_ms =
+ QPNP_LUT_RAMP_STEP_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
+ if (!rc)
+ pwm_cfg->lut_params.ramp_step_ms = val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ pwm_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
+ rc = of_property_read_u32(node, "qcom,lut-flags", &val);
+ if (!rc)
+ pwm_cfg->lut_params.flags = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ pwm_cfg->lut_params.idx_len =
+ pwm_cfg->duty_cycles->num_duty_pcts;
+ }
+ return 0;
+};
+
+static int qpnp_led_get_mode(const char *mode)
+{
+ if (strncmp(mode, "manual", strlen(mode)) == 0)
+ return MANUAL_MODE;
+ else if (strncmp(mode, "pwm", strlen(mode)) == 0)
+ return PWM_MODE;
+ else if (strncmp(mode, "lpg", strlen(mode)) == 0)
+ return LPG_MODE;
+ else
+ return -EINVAL;
+};
+
static int __devinit qpnp_get_config_kpdbl(struct qpnp_led_data *led,
struct device_node *node)
{
int rc;
u32 val;
+ u8 led_mode;
+ const char *mode;
led->kpdbl_cfg = devm_kzalloc(&led->spmi_dev->dev,
sizeof(struct kpdbl_config_data), GFP_KERNEL);
@@ -1681,28 +1870,28 @@
dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
-
- rc = of_property_read_u32(node, "qcom,mode", &val);
- if (!rc)
- led->kpdbl_cfg->mode = (u8) val;
- else
+ rc = of_property_read_string(node, "qcom,mode", &mode);
+ if (!rc) {
+ led_mode = qpnp_led_get_mode(mode);
+ if ((led_mode == MANUAL_MODE) || (led_mode == -EINVAL)) {
+ dev_err(&led->spmi_dev->dev, "Selected mode not " \
+ "supported for kpdbl.\n");
+ return -EINVAL;
+ }
+ led->kpdbl_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
+ sizeof(struct pwm_config_data),
+ GFP_KERNEL);
+ if (!led->kpdbl_cfg->pwm_cfg) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ led->kpdbl_cfg->pwm_cfg->mode = led_mode;
+ } else
return rc;
- if (led->kpdbl_cfg->mode == LPG_MODE) {
- dev_err(&led->spmi_dev->dev, "LPG mode not supported\n");
- return -EINVAL;
- }
-
- rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
- if (!rc)
- led->kpdbl_cfg->pwm_channel = (u8) val;
- else
- return rc;
-
- rc = of_property_read_u32(node, "qcom,pwm-us", &val);
- if (!rc)
- led->kpdbl_cfg->pwm_period_us = val;
- else
+ rc = qpnp_get_config_pwm(led->kpdbl_cfg->pwm_cfg, led->spmi_dev, node);
+ if (rc < 0)
return rc;
rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
@@ -1729,10 +1918,9 @@
static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
struct device_node *node)
{
- struct property *prop;
- int rc, i;
- u32 val;
- u8 *temp_cfg;
+ int rc;
+ u8 led_mode;
+ const char *mode;
led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
sizeof(struct rgb_config_data), GFP_KERNEL);
@@ -1750,113 +1938,29 @@
else
return -EINVAL;
- rc = of_property_read_u32(node, "qcom,mode", &val);
- if (!rc)
- led->rgb_cfg->mode = (u8) val;
- else
- return rc;
-
- rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
- if (!rc)
- led->rgb_cfg->pwm_channel = val;
- else
- return rc;
-
- if (led->rgb_cfg->mode == PWM_MODE) {
- rc = of_property_read_u32(node, "qcom,pwm-us", &val);
- if (!rc)
- led->rgb_cfg->pwm_period_us = val;
- else
- return rc;
- }
-
- if (led->rgb_cfg->mode == LPG_MODE) {
- led->rgb_cfg->duty_cycles =
- devm_kzalloc(&led->spmi_dev->dev,
- sizeof(struct pwm_duty_cycles), GFP_KERNEL);
- if (!led->rgb_cfg->duty_cycles) {
- dev_err(&led->spmi_dev->dev,
- "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- prop = of_find_property(node, "qcom,duty-pcts",
- &led->rgb_cfg->duty_cycles->num_duty_pcts);
- if (!prop) {
- dev_err(&led->spmi_dev->dev, "Looking up property " \
- "node qcom,duty-pcts failed\n");
- return -ENODEV;
- } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
- dev_err(&led->spmi_dev->dev, "Invalid length of " \
- "duty pcts\n");
+ rc = of_property_read_string(node, "qcom,mode", &mode);
+ if (!rc) {
+ led_mode = qpnp_led_get_mode(mode);
+ if ((led_mode == MANUAL_MODE) || (led_mode == -EINVAL)) {
+ dev_err(&led->spmi_dev->dev, "Selected mode not " \
+ "supported for rgb.\n");
return -EINVAL;
}
-
- led->rgb_cfg->duty_cycles->duty_pcts =
- devm_kzalloc(&led->spmi_dev->dev,
- sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
- GFP_KERNEL);
- if (!led->rgb_cfg->duty_cycles->duty_pcts) {
+ led->rgb_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
+ sizeof(struct pwm_config_data),
+ GFP_KERNEL);
+ if (!led->rgb_cfg->pwm_cfg) {
dev_err(&led->spmi_dev->dev,
"Unable to allocate memory\n");
return -ENOMEM;
}
+ led->rgb_cfg->pwm_cfg->mode = led_mode;
+ } else
+ return rc;
- temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
- led->rgb_cfg->duty_cycles->num_duty_pcts *
- sizeof(u8), GFP_KERNEL);
- if (!temp_cfg) {
- dev_err(&led->spmi_dev->dev, "Failed to allocate " \
- "memory for duty pcts\n");
- return -ENOMEM;
- }
-
- memcpy(temp_cfg, prop->value,
- led->rgb_cfg->duty_cycles->num_duty_pcts);
-
- for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
- led->rgb_cfg->duty_cycles->duty_pcts[i] =
- (int) temp_cfg[i];
-
- rc = of_property_read_u32(node, "qcom,start-idx", &val);
- if (!rc) {
- led->rgb_cfg->lut_params.start_idx = val;
- led->rgb_cfg->duty_cycles->start_idx = val;
- } else
- return rc;
-
- led->rgb_cfg->lut_params.lut_pause_hi = 0;
- rc = of_property_read_u32(node, "qcom,pause-hi", &val);
- if (!rc)
- led->rgb_cfg->lut_params.lut_pause_hi = val;
- else if (rc != -EINVAL)
- return rc;
-
- led->rgb_cfg->lut_params.lut_pause_lo = 0;
- rc = of_property_read_u32(node, "qcom,pause-lo", &val);
- if (!rc)
- led->rgb_cfg->lut_params.lut_pause_lo = val;
- else if (rc != -EINVAL)
- return rc;
-
- led->rgb_cfg->lut_params.ramp_step_ms =
- QPNP_LUT_RAMP_STEP_DEFAULT;
- rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
- if (!rc)
- led->rgb_cfg->lut_params.ramp_step_ms = val;
- else if (rc != -EINVAL)
- return rc;
-
- led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
- rc = of_property_read_u32(node, "qcom,lut-flags", &val);
- if (!rc)
- led->rgb_cfg->lut_params.flags = val;
- else if (rc != -EINVAL)
- return rc;
-
- led->rgb_cfg->lut_params.idx_len =
- led->rgb_cfg->duty_cycles->num_duty_pcts;
- }
+ rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->spmi_dev, node);
+ if (rc < 0)
+ return rc;
return 0;
}
@@ -1866,6 +1970,8 @@
{
int rc;
u32 val;
+ u8 led_mode;
+ const char *mode;
led->mpp_cfg = devm_kzalloc(&led->spmi_dev->dev,
sizeof(struct mpp_config_data), GFP_KERNEL);
@@ -1895,6 +2001,33 @@
else if (rc != -EINVAL)
return rc;
+ rc = of_property_read_string(node, "qcom,mode", &mode);
+ if (!rc) {
+ led_mode = qpnp_led_get_mode(mode);
+ led->mpp_cfg->pwm_mode = led_mode;
+ if (led_mode == MANUAL_MODE)
+ return MANUAL_MODE;
+ else if (led_mode == -EINVAL) {
+ dev_err(&led->spmi_dev->dev, "Selected mode not " \
+ "supported for mpp.\n");
+ return -EINVAL;
+ }
+ led->mpp_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
+ sizeof(struct pwm_config_data),
+ GFP_KERNEL);
+ if (!led->mpp_cfg->pwm_cfg) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ led->mpp_cfg->pwm_cfg->mode = led_mode;
+ } else
+ return rc;
+
+ rc = qpnp_get_config_pwm(led->mpp_cfg->pwm_cfg, led->spmi_dev, node);
+ if (rc < 0)
+ return rc;
+
return 0;
}
@@ -2005,6 +2138,7 @@
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Unable to read mpp config data\n");
+ goto fail_id_check;
}
} else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
rc = qpnp_get_config_kpdbl(led, temp);
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index fcade49..2c2b339 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -75,7 +75,8 @@
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
DMX_MISSED_ERROR, /* Receiver missed packet */
DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */
- DMX_OK_IDX /* Received OK, new index event */
+ DMX_OK_IDX, /* Received OK, new index event */
+ DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */
} ;
@@ -135,6 +136,7 @@
} marker;
struct dmx_index_event_info idx_event;
+ struct dmx_scrambling_status_event_info scrambling_bits;
};
};
@@ -250,6 +252,7 @@
int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
char *data, size_t size);
+ int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value);
};
/*--------------------------------------------------------------------------*/
@@ -300,6 +303,7 @@
struct dmx_secure_mode *sec_mode);
int (*oob_command) (struct dmx_section_feed *feed,
struct dmx_oob_command *cmd);
+ int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 2a750a6..6734da8 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1796,6 +1796,35 @@
return 0;
}
+static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter,
+ struct dmx_scrambling_bits *scrambling_bits)
+{
+ struct dmxdev_feed *feed;
+
+ if (!scrambling_bits ||
+ (filter->state != DMXDEV_STATE_GO))
+ return -EINVAL;
+
+ if (filter->type == DMXDEV_TYPE_SEC) {
+ if (filter->feed.sec.feed->get_scrambling_bits)
+ return filter->feed.sec.feed->get_scrambling_bits(
+ filter->feed.sec.feed,
+ &scrambling_bits->value);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ if (feed->pid == scrambling_bits->pid) {
+ if (feed->ts->get_scrambling_bits)
+ return feed->ts->get_scrambling_bits(feed->ts,
+ &scrambling_bits->value);
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
{
struct ts_insertion_buffer *ts_buffer =
@@ -2519,6 +2548,13 @@
dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
spin_unlock(&dmxdevfilter->dev->lock);
wake_up_all(&dmxdevfilter->buffer.queue);
+ } else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+ event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+ event.params.scrambling_status =
+ dmx_data_ready->scrambling_bits;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
} else {
spin_unlock(&dmxdevfilter->dev->lock);
}
@@ -2635,6 +2671,16 @@
return 0;
}
+ if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+ event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+ event.params.scrambling_status =
+ dmx_data_ready->scrambling_bits;
+ dvb_dmxdev_add_event(events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+ }
+
if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
event.type = DMX_EVENT_NEW_ES_DATA;
event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
@@ -3938,6 +3984,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_GET_SCRAMBLING_BITS:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -4193,6 +4248,7 @@
struct dmxdev_filter *filter;
int active_count = 0;
struct dmx_buffer_status buffer_status;
+ struct dmx_scrambling_bits scrambling_bits;
const char *pes_feeds[] = {"DEC", "PES", "DVR", "REC"};
if (!dmxdev)
@@ -4209,23 +4265,32 @@
seq_printf(s, "type: SEC, ");
seq_printf(s, "PID %04d ",
filter->params.sec.pid);
+ scrambling_bits.pid = filter->params.sec.pid;
} else {
seq_printf(s, "type: %s, ",
pes_feeds[filter->params.pes.output]);
seq_printf(s, "PID: %04d ",
filter->params.pes.pid);
+ scrambling_bits.pid = filter->params.pes.pid;
}
+ dvb_dmxdev_get_scrambling_bits(filter,
+ &scrambling_bits);
+
if (0 == dvb_dmxdev_get_buffer_status(
filter, &buffer_status)) {
seq_printf(s, "size: %08d, ",
buffer_status.size);
seq_printf(s, "fullness: %08d, ",
buffer_status.fullness);
- seq_printf(s, "error: %d\n",
+ seq_printf(s, "error: %d, ",
buffer_status.error);
+ seq_printf(s, "scramble: %d\n",
+ scrambling_bits.value);
+
} else {
- seq_printf(s, "\n");
+ seq_printf(s, "scramble: %d\n",
+ scrambling_bits.value);
}
}
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 9844c64..b8c3c44 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -164,6 +164,11 @@
return ((buf[1] & 0x1f) << 8) + buf[2];
}
+static inline u16 ts_scrambling_ctrl(const u8 *buf)
+{
+ return (buf[3] >> 6) & 0x3;
+}
+
static inline u8 payload(const u8 *tsp)
{
if (!(tsp[3] & 0x10)) // no payload?
@@ -1287,6 +1292,32 @@
static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
const u8 *buf, const u8 timestamp[TIMESTAMP_LEN])
{
+ u16 pid = ts_pid(buf);
+ u8 scrambling_bits = ts_scrambling_ctrl(buf);
+ struct dmx_data_ready dmx_data_ready;
+
+ /*
+ * Notify on scrambling status change only when we move
+ * from clear (0) to non-clear and vise-versa
+ */
+ if ((scrambling_bits && !feed->scrambling_bits) ||
+ (!scrambling_bits && feed->scrambling_bits)) {
+ dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS;
+ dmx_data_ready.data_length = 0;
+ dmx_data_ready.scrambling_bits.pid = pid;
+ dmx_data_ready.scrambling_bits.old_value =
+ feed->scrambling_bits;
+ dmx_data_ready.scrambling_bits.new_value = scrambling_bits;
+
+ if (feed->type == DMX_TYPE_SEC)
+ feed->data_ready_cb.sec(&feed->filter->filter,
+ &dmx_data_ready);
+ else
+ feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+ }
+
+ feed->scrambling_bits = scrambling_bits;
+
switch (feed->type) {
case DMX_TYPE_TS:
if (!feed->feed.ts.is_filtering)
@@ -1546,9 +1577,11 @@
if (pktsize == 192) {
if (leadingbytes)
- memcpy(timestamp, &buf[p], TIMESTAMP_LEN);
+ memcpy(timestamp, &demux->tsbuf[p],
+ TIMESTAMP_LEN);
else
- memcpy(timestamp, &buf[188], TIMESTAMP_LEN);
+ memcpy(timestamp, &demux->tsbuf[188],
+ TIMESTAMP_LEN);
} else {
memset(timestamp, 0, TIMESTAMP_LEN);
}
@@ -2047,6 +2080,7 @@
}
feed->first_cc = 1;
+ feed->scrambling_bits = 0;
if ((feed->ts_type & TS_PACKET) &&
!(feed->ts_type & TS_PAYLOAD_ONLY)) {
@@ -2302,6 +2336,25 @@
return ret;
}
+static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed,
+ u8 *value)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+
+ if (!ts_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return -EINVAL;
+ }
+
+ *value = feed->scrambling_bits;
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
char *data, size_t size)
{
@@ -2391,6 +2444,7 @@
(*ts_feed)->notify_data_read = NULL;
(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+ (*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits;
(*ts_feed)->ts_insertion_init = NULL;
(*ts_feed)->ts_insertion_terminate = NULL;
(*ts_feed)->ts_insertion_insert_buffer =
@@ -2557,6 +2611,7 @@
dvbdmxfeed->feed.sec.secbufp = 0;
dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->first_cc = 1;
+ dvbdmxfeed->scrambling_bits = 0;
if (!dvbdmx->start_feed) {
mutex_unlock(&dvbdmx->mutex);
@@ -2723,6 +2778,25 @@
return ret;
}
+static int dvbdmx_section_get_scrambling_bits(
+ struct dmx_section_feed *section_feed, u8 *value)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+
+ if (!section_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return -EINVAL;
+ }
+
+ *value = feed->scrambling_bits;
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
struct dmx_section_feed **feed,
dmx_section_cb callback)
@@ -2763,6 +2837,7 @@
(*feed)->notify_data_read = NULL;
(*feed)->set_secure_mode = dmx_section_set_secure_mode;
(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
+ (*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
mutex_unlock(&dvbdmx->mutex);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 879aad2..9fb1a12 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -187,6 +187,8 @@
int first_cc;
int pusi_seen; /* prevents feeding of garbage from previous section */
+ u8 scrambling_bits;
+
struct dvb_demux_rec_info *rec_info;
u64 prev_tsp_num;
u64 prev_stc;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 4579cee..08fa7dd 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -539,7 +539,6 @@
rc = msm_create_session(pvdev->vdev->num, pvdev->vdev);
if (rc < 0)
goto session_fail;
-
rc = msm_create_command_ack_q(pvdev->vdev->num, 0);
if (rc < 0)
goto command_ack_q_fail;
@@ -611,6 +610,7 @@
/* Donot wait, imaging server may have crashed */
msm_post_event(&event, -1);
+ msm_delete_command_ack_q(pvdev->vdev->num, 0);
/* This should take care of both normal close
* and application crashes */
@@ -622,7 +622,6 @@
/* Donot wait, imaging server may have crashed */
msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
-
msm_delete_command_ack_q(pvdev->vdev->num,
sp->stream_id);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 59858b5..88f2f08 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -80,13 +80,20 @@
}
static uint32_t msm_isp_get_buf_handle(
- struct msm_isp_buf_mgr *buf_mgr)
+ struct msm_isp_buf_mgr *buf_mgr,
+ uint32_t session_id, uint32_t stream_id)
{
int i;
if ((buf_mgr->buf_handle_cnt << 8) == 0)
buf_mgr->buf_handle_cnt++;
for (i = 0; i < buf_mgr->num_buf_q; i++) {
+ if (buf_mgr->bufq[i].session_id == session_id &&
+ buf_mgr->bufq[i].stream_id == stream_id)
+ return 0;
+ }
+
+ for (i = 0; i < buf_mgr->num_buf_q; i++) {
if (buf_mgr->bufq[i].bufq_handle == 0) {
memset(&buf_mgr->bufq[i],
0, sizeof(struct msm_isp_bufq));
@@ -604,7 +611,8 @@
return rc;
}
- buf_request->handle = msm_isp_get_buf_handle(buf_mgr);
+ buf_request->handle = msm_isp_get_buf_handle(buf_mgr,
+ buf_request->session_id, buf_request->stream_id);
if (!buf_request->handle) {
pr_err("Invalid buffer handle\n");
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index b31b3f1..ff9c9b8 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -121,6 +121,7 @@
vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE;
vfe_dev->subdev.sd.entity.name = pdev->name;
+ vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
rc = msm_sd_register(&vfe_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 7bc2b7d..6de6e74 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -38,6 +38,8 @@
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
+#define VFE_MAX_CFG_TIMEOUT 3000
+
struct vfe_device;
struct msm_vfe_axi_stream;
struct msm_vfe_stats_stream;
@@ -88,7 +90,7 @@
void (*enable_wm) (struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
void (*cfg_io_format) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd);
+ struct msm_vfe_axi_stream *stream_info);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*clear_framedrop) (struct vfe_device *vfe_dev,
@@ -103,13 +105,13 @@
struct msm_vfe_axi_stream *stream_info);
void (*cfg_wm_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
@@ -231,7 +233,8 @@
enum msm_vfe_axi_stream_src stream_src;
uint8_t num_planes;
uint8_t wm[MAX_PLANES_PER_STREAM];
- uint32_t plane_offset[MAX_PLANES_PER_STREAM];
+ uint32_t output_format;/*Planar/RAW/Misc*/
+ struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
uint8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 679c5cb..3a94af3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -441,11 +441,11 @@
}
static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int bpp, bpp_reg = 0;
uint32_t io_format_reg;
- bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+ bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
switch (bpp) {
case 8:
@@ -459,7 +459,7 @@
break;
}
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
- switch (stream_req_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case CAMIF_RAW:
io_format_reg &= 0xFFFFCFFF;
io_format_reg |= bpp_reg << 12;
@@ -565,44 +565,40 @@
static void msm_vfe32_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
uint32_t val;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
/*WR_BUFFER_CFG*/
val =
msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
val =
msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
}
@@ -624,19 +620,15 @@
static void msm_vfe32_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
- uint8_t plane_idx)
+ struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
+ &stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
- switch (stream_cfg_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case PIX_ENCODER:
case PIX_VIEWFINDER: {
if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -644,7 +636,7 @@
/*SINGLE_STREAM_SEL*/
xbar_cfg |= plane_cfg->output_plane_format << 5;
} else {
- switch (stream_cfg_cmd->output_format) {
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
@@ -652,7 +644,7 @@
}
xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/
}
- if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+ if (stream_info->stream_src == PIX_VIEWFINDER)
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 94041ea..c4a1b63 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -523,14 +523,14 @@
comp_mask &= ~(0x7F << (comp_mask_index * 8));
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << (comp_mask_index * 8));
- if (stream_info->plane_offset[0])
+ if (stream_info->plane_cfg[0].plane_addr_offset)
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask |= 1 << (comp_mask_index + 25);
- if (stream_info->plane_offset[0] && (comp_mask >> 24))
+ if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
irq_mask |= BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -544,14 +544,14 @@
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
- if (stream_info->plane_offset[0])
+ if (stream_info->plane_cfg[0].plane_addr_offset)
comp_mask &= ~(axi_data->composite_info[comp_mask_index].
stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask &= ~(1 << (comp_mask_index + 25));
- if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+ if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
irq_mask &= ~BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -614,11 +614,11 @@
}
static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int bpp, bpp_reg = 0;
uint32_t io_format_reg;
- bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+ bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
switch (bpp) {
case 8:
@@ -632,7 +632,7 @@
break;
}
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
- switch (stream_req_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case CAMIF_RAW:
io_format_reg &= 0xFFFFCFFF;
io_format_reg |= bpp_reg << 12;
@@ -753,43 +753,39 @@
static void msm_vfe40_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
uint32_t val;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
/*WR_BUFFER_CFG*/
val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
+ msm_isp_cal_word_per_line(stream_info->output_format,
+ stream_info->plane_cfg[
plane_idx].output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[
+ (stream_info->plane_cfg[
plane_idx].output_height - 1) << 4 |
VFE40_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
+ msm_isp_cal_word_per_line(stream_info->output_format,
+ stream_info->plane_cfg[
plane_idx].output_width) << 16 |
- (stream_cfg_cmd->plane_cfg[
+ (stream_info->plane_cfg[
plane_idx].output_height - 1) << 4 |
VFE40_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
@@ -821,20 +817,16 @@
static void msm_vfe40_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
+ &stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
- switch (stream_cfg_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case PIX_ENCODER:
case PIX_VIEWFINDER: {
if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -842,7 +834,7 @@
/*SINGLE_STREAM_SEL*/
xbar_cfg |= plane_cfg->output_plane_format << 8;
} else {
- switch (stream_cfg_cmd->output_format) {
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
@@ -850,7 +842,7 @@
}
xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
}
- if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+ if (stream_info->stream_src == PIX_VIEWFINDER)
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 13160ee..e3d036f6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -136,23 +136,23 @@
}
for (i = 0; i < stream_info->num_planes; i++) {
- stream_info->plane_offset[i] =
- stream_cfg_cmd->plane_cfg[i].plane_addr_offset;
+ stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i];
stream_info->max_width = max(stream_info->max_width,
stream_cfg_cmd->plane_cfg[i].output_width);
}
+ stream_info->output_format = stream_cfg_cmd->output_format;
stream_info->stream_src = stream_cfg_cmd->stream_src;
stream_info->frame_based = stream_cfg_cmd->frame_base;
return 0;
}
static uint32_t msm_isp_axi_get_plane_size(
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, int plane_idx)
+ struct msm_vfe_axi_stream *stream_info, int plane_idx)
{
uint32_t size = 0;
- struct msm_vfe_axi_plane_cfg *plane_cfg = stream_cfg_cmd->plane_cfg;
- switch (stream_cfg_cmd->output_format) {
+ struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -211,21 +211,17 @@
}
void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int i, j;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-
for (i = 0; i < stream_info->num_planes; i++) {
for (j = 0; j < axi_data->hw_info->num_wm; j++) {
if (!axi_data->free_wm[j]) {
axi_data->free_wm[j] =
- stream_cfg_cmd->axi_stream_handle;
+ stream_info->stream_handle;
axi_data->wm_image_size[j] =
msm_isp_axi_get_plane_size(
- stream_cfg_cmd, i);
+ stream_info, i);
axi_data->num_used_wm++;
break;
}
@@ -246,20 +242,17 @@
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int i;
uint8_t comp_mask = 0;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
for (i = 0; i < stream_info->num_planes; i++)
comp_mask |= 1 << stream_info->wm[i];
for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
if (!axi_data->composite_info[i].stream_handle) {
axi_data->composite_info[i].stream_handle =
- stream_cfg_cmd->axi_stream_handle;
+ stream_info->stream_handle;
axi_data->composite_info[i].
stream_composite_mask = comp_mask;
axi_data->num_used_composite_mask++;
@@ -384,7 +377,7 @@
break;
}
- sof_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+ sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
@@ -471,18 +464,18 @@
stream_info = &vfe_dev->axi_data.
stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
- msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
+ msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info);
if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
stream_cfg_cmd->stream_src == IDEAL_RAW)
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_io_format(vfe_dev, stream_cfg_cmd);
+ cfg_io_format(vfe_dev, stream_info);
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
if (stream_info->num_planes > 1) {
msm_isp_axi_reserve_comp_mask(
- &vfe_dev->axi_data, stream_cfg_cmd);
+ &vfe_dev->axi_data, stream_info);
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_comp_mask(vfe_dev, stream_info);
} else {
@@ -492,10 +485,10 @@
for (i = 0; i < stream_info->num_planes; i++) {
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_reg(vfe_dev, stream_info, i);
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_xbar_reg(vfe_dev, stream_info, i);
}
return rc;
}
@@ -610,7 +603,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
VFE_PONG_FLAG, buf->mapped_info[i].paddr +
- stream_info->plane_offset[i]);
+ stream_info->plane_cfg[i].plane_addr_offset);
stream_info->buf[1] = buf;
}
@@ -657,7 +650,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
pingpong_status, buf->mapped_info[i].paddr +
- stream_info->plane_offset[i]);
+ stream_info->plane_cfg[i].plane_addr_offset);
pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
stream_info->buf[pingpong_bit] = buf;
@@ -852,7 +845,7 @@
spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stream_config_complete,
- msecs_to_jiffies(500));
+ msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
@@ -976,18 +969,33 @@
enum msm_isp_camif_update_state camif_update)
{
int i, rc = 0;
+ uint8_t wait_for_complete = 0;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+
stream_info->state = STOP_PENDING;
+ if (stream_info->stream_type == BURST_STREAM &&
+ stream_info->runtime_num_burst_capture == 0) {
+ /*Configure AXI writemasters to stop immediately
+ *since for burst case, write masters already skip
+ *all frames.
+ */
+ msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
+ stream_info->state = INACTIVE;
+ } else {
+ wait_for_complete = 1;
+ }
}
- rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
- if (rc < 0) {
- pr_err("%s: wait for config done failed\n", __func__);
- return rc;
+ if (wait_for_complete) {
+ rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
+ if (rc < 0) {
+ pr_err("%s: wait for config done failed\n", __func__);
+ return rc;
+ }
}
msm_isp_update_stream_bandwidth(vfe_dev);
if (camif_update == DISABLE_CAMIF)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index f592a60..3d775f9 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -27,15 +27,11 @@
void msm_isp_axi_reserve_wm(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
-
-void msm_isp_axi_reserve_rdi(
- struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_axi_stream *stream_info);
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_axi_stream *stream_info);
int msm_isp_axi_check_stream_state(
struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index ce71235..d857a14 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -343,7 +343,7 @@
atomic_set(&vfe_dev->stats_data.stats_update, 2);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stats_config_complete,
- msecs_to_jiffies(500));
+ msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index dd8db03..ee205c0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -389,6 +389,11 @@
rc = msm_isp_update_axi_stream(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
+ case MSM_SD_SHUTDOWN:
+ while (vfe_dev->vfe_open_cnt != 0)
+ msm_isp_close_node(sd, NULL);
+ break;
+
default:
pr_err("%s: Invalid ISP command\n", __func__);
rc = -EINVAL;
@@ -912,11 +917,10 @@
rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
if (rc <= 0)
- pr_err("%s: halt timeout\n", __func__);
+ pr_err("%s: halt timeout rc=%ld\n", __func__, rc);
vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
-
vfe_dev->vfe_open_cnt--;
mutex_unlock(&vfe_dev->core_mutex);
mutex_unlock(&vfe_dev->realtime_mutex);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index a95eda7..dc1bcc3 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -91,7 +91,6 @@
BUG_ON(!ispif);
memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
-
for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT,
@@ -105,9 +104,13 @@
ISPIF_VFE_m_IRQ_CLEAR_1(i));
msm_camera_io_w(0xFFFFFFFF, ispif->base +
ISPIF_VFE_m_IRQ_CLEAR_2(i));
+
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i));
- msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
- msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
+
+ msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+ ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
+ msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+ ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
@@ -905,6 +908,12 @@
switch (cmd) {
case VIDIOC_MSM_ISPIF_CFG:
return msm_ispif_cmd(sd, arg);
+ case MSM_SD_SHUTDOWN: {
+ struct ispif_device *ispif =
+ (struct ispif_device *)v4l2_get_subdevdata(sd);
+ msm_ispif_release(ispif);
+ return 0;
+ }
default:
pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
return -ENOIOCTLCMD;
@@ -986,6 +995,7 @@
ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF;
ispif->msm_sd.sd.entity.name = pdev->name;
+ ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1;
rc = msm_sd_register(&ispif->msm_sd);
if (rc) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
index c805c3d..3cc21a7 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -91,4 +91,6 @@
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
+#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA
+
#endif /* __MSM_ISPIF_HWREG_V2_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index be9f613..5581723 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -31,6 +31,7 @@
#include "msm_sd.h"
static struct v4l2_device *msm_v4l2_dev;
+static struct list_head ordered_sd_list;
static struct msm_queue_head *msm_session_q;
@@ -301,6 +302,20 @@
return rc;
}
+static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev,
+ struct list_head *sd_list)
+{
+ struct msm_sd_subdev *temp_sd;
+
+ list_for_each_entry(temp_sd, sd_list, list) {
+ if (msm_subdev->close_seq < temp_sd->close_seq) {
+ list_add_tail(&msm_subdev->list, &temp_sd->list);
+ return;
+ }
+ }
+ list_add_tail(&msm_subdev->list, sd_list);
+}
+
int msm_sd_register(struct msm_sd_subdev *msm_subdev)
{
if (WARN_ON(!msm_subdev))
@@ -309,6 +324,7 @@
if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
return -EIO;
+ msm_add_sd_in_position(msm_subdev, &ordered_sd_list);
return __msm_sd_register_subdev(&msm_subdev->sd);
}
@@ -397,66 +413,40 @@
spin_lock_irqsave(&(session->command_ack_q.lock), flags);
list_del_init(&cmd_ack->list);
+ kzfree(cmd_ack);
session->command_ack_q.len--;
spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
}
-static inline int __msm_v4l2_subdev_shutdown(struct v4l2_subdev *sd)
-{
- return 0;
-}
-
-static void msm_sd_try_shutdown(void)
-{
- unsigned long flags;
- struct v4l2_subdev *sd;
-
- /* release all subdev's resource */
- spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
- if (!list_empty(&msm_v4l2_dev->subdevs)) {
- list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
- __msm_v4l2_subdev_shutdown(sd);
- }
- spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
-}
-
-static inline int __msm_sd_close_session_streams(struct v4l2_subdev *sd,
+static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd,
struct msm_sd_close_ioctl *sd_close)
{
+ struct v4l2_subdev *sd;
+ sd = &msm_sd->sd;
+ pr_debug("%s: Shutting down subdev %s", __func__, sd->name);
+
+ v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close);
+ v4l2_subdev_call(sd, core, s_power, 0);
+
return 0;
}
static inline int __msm_destroy_session_streams(void *d1, void *d2)
{
struct msm_stream *stream = d1;
- struct msm_sd_close_ioctl *sd_close = d2;
- struct v4l2_subdev *sd;
- unsigned long flags;
- sd_close->stream = stream->stream_id;
-
- spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
- if (!list_empty(&msm_v4l2_dev->subdevs))
- list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
- __msm_sd_close_session_streams(sd, sd_close);
- spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
INIT_LIST_HEAD(&stream->queued_list);
return 0;
}
static void msm_destroy_session_streams(struct msm_session *session)
{
- struct msm_sd_close_ioctl sd_close;
- /* to ensure error handling purpose, it needs to detach all subdevs
- * which are being connected to streams */
if (!session)
return;
- sd_close.session = session->session_id;
-
msm_queue_traverse_action(&session->stream_q, struct msm_stream, list,
- __msm_destroy_session_streams, &sd_close);
+ __msm_destroy_session_streams, NULL);
msm_queue_drain(&session->stream_q, struct msm_stream, list);
}
@@ -694,16 +684,13 @@
struct msm_v4l2_event_data *event_data =
(struct msm_v4l2_event_data *)&event.u.data[0];
struct msm_session *session = d1;
- mutex_lock(&session->lock);
+
event.type = MSM_CAMERA_V4L2_EVENT_TYPE;
event.id = MSM_CAMERA_MSM_NOTIFY;
event_data->command = MSM_CAMERA_PRIV_SHUTDOWN;
v4l2_event_queue(session->event_q.vdev, &event);
- msm_destroy_session_streams(session);
- msm_remove_session_cmd_ack_q(session);
- mutex_unlock(&session->lock);
return 0;
}
@@ -712,22 +699,23 @@
int rc = 0;
unsigned long flags;
struct msm_video_device *pvdev = video_drvdata(filep);
+ struct msm_sd_close_ioctl sd_close;
+ struct msm_sd_subdev *msm_sd;
- /* 1st thing 1st, send v4l2_event to HAL immediately,
- * to ensure error handling purpose, it needs to detach all subdevs
- * which are being connected to streams */
+ /*stop all hardware blocks immediately*/
+ if (!list_empty(&msm_v4l2_dev->subdevs))
+ list_for_each_entry(msm_sd, &ordered_sd_list, list)
+ __msm_sd_close_subdevs(msm_sd, &sd_close);
+
+ /* send v4l2_event to HAL next*/
msm_queue_traverse_action(msm_session_q, struct msm_session, list,
__msm_close_destry_session_notify_apps, NULL);
- msm_queue_drain(msm_session_q, struct msm_session, list);
-
spin_lock_irqsave(&msm_eventq_lock, flags);
msm_eventq = NULL;
spin_unlock_irqrestore(&msm_eventq_lock, flags);
v4l2_fh_release(filep);
- msm_sd_try_shutdown();
-
spin_lock_irqsave(&msm_pid_lock, flags);
put_pid(msm_pid);
msm_pid = NULL;
@@ -754,7 +742,6 @@
int rc;
unsigned long flags;
struct msm_video_device *pvdev = video_drvdata(filep);
-
BUG_ON(!pvdev);
/* !!! only ONE open is allowed !!! */
@@ -990,7 +977,7 @@
msm_init_queue(msm_session_q);
spin_lock_init(&msm_eventq_lock);
spin_lock_init(&msm_pid_lock);
-
+ INIT_LIST_HEAD(&ordered_sd_list);
goto probe_end;
v4l2_fail:
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index b0ff832..895f452 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -161,6 +161,7 @@
msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
msm_buf_mngr_dev->subdev.sd.entity.group_id =
MSM_CAMERA_SUBDEV_BUF_MNGR;
+ msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/msm_sd.h b/drivers/media/platform/msm/camera_v2/msm_sd.h
index 958e030..7c1519d 100644
--- a/drivers/media/platform/msm/camera_v2/msm_sd.h
+++ b/drivers/media/platform/msm/camera_v2/msm_sd.h
@@ -50,10 +50,12 @@
#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000
#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000
#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000
+#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000
struct msm_sd_subdev {
struct v4l2_subdev sd;
int close_seq;
+ struct list_head list;
};
struct msm_sd_req_sd {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 5a174f5..4dd3f3d 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -43,6 +43,9 @@
#define CONFIG_MSM_CPP_DBG 0
+/* dump the frame command before writing to the hardware */
+#define MSM_CPP_DUMP_FRM_CMD 0
+
#if CONFIG_MSM_CPP_DBG
#define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
#else
@@ -208,7 +211,6 @@
pr_err("ION import failed\n");
goto QUEUE_BUFF_ERROR1;
}
-
rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle,
cpp_dev->domain_num, 0, SZ_4K, 0,
(unsigned long *)&buff->map_info.phy_addr,
@@ -237,6 +239,7 @@
static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
struct msm_cpp_buffer_map_list_t *buff)
{
+
ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
cpp_dev->domain_num, 0);
ion_free(cpp_dev->client, buff->map_info.ion_handle);
@@ -390,6 +393,8 @@
pr_err("Queue not free sessionid: %d, streamid: %d\n",
cpp_dev->buff_queue[i].session_id,
cpp_dev->buff_queue[i].stream_id);
+ msm_cpp_dequeue_buff_info_list
+ (cpp_dev, &cpp_dev->buff_queue[i]);
msm_cpp_free_buff_queue_entry(cpp_dev,
cpp_dev->buff_queue[i].session_id,
cpp_dev->buff_queue[i].stream_id);
@@ -821,9 +826,16 @@
{
uint32_t i;
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+
mutex_lock(&cpp_dev->mutex);
+
+ if (cpp_dev->cpp_open_cnt == 0) {
+ mutex_unlock(&cpp_dev->mutex);
+ return 0;
+ }
+
for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
- if (cpp_dev->cpp_subscribe_list[i].vfh == &fh->vfh) {
+ if (cpp_dev->cpp_subscribe_list[i].active == 1) {
cpp_dev->cpp_subscribe_list[i].active = 0;
cpp_dev->cpp_subscribe_list[i].vfh = NULL;
break;
@@ -835,7 +847,6 @@
return -ENODEV;
}
- CPP_DBG("close %d %p\n", i, &fh->vfh);
cpp_dev->cpp_open_cnt--;
if (cpp_dev->cpp_open_cnt == 0) {
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
@@ -843,6 +854,7 @@
cpp_release_hardware(cpp_dev);
cpp_dev->state = CPP_STATE_OFF;
}
+
mutex_unlock(&cpp_dev->mutex);
return 0;
}
@@ -888,8 +900,7 @@
event_qcmd->command = processed_frame;
CPP_DBG("fid %d\n", processed_frame->frame_id);
msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
-
- if (!processed_frame->output_buffer_info.processed_divert) {
+ if (!processed_frame->output_buffer_info[0].processed_divert) {
memset(&buff_mgr_info, 0 ,
sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id =
@@ -899,7 +910,7 @@
buff_mgr_info.frame_id = processed_frame->frame_id;
buff_mgr_info.timestamp = processed_frame->timestamp;
buff_mgr_info.index =
- processed_frame->output_buffer_info.index;
+ processed_frame->output_buffer_info[0].index;
rc = msm_cpp_buffer_ops(cpp_dev,
VIDIOC_MSM_BUF_MNGR_BUF_DONE,
&buff_mgr_info);
@@ -908,6 +919,28 @@
rc = -EINVAL;
}
}
+
+ if (processed_frame->duplicate_output &&
+ !processed_frame->
+ output_buffer_info[1].processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->duplicate_identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->duplicate_identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info[1].index;
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
+ }
v4l2_evt.id = processed_frame->inst_id;
v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
@@ -915,6 +948,23 @@
return rc;
}
+#if MSM_CPP_DUMP_FRM_CMD
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+ int i;
+ pr_err("%s: -------- cpp frame cmd msg start --------", __func__);
+ for (i = 0; i < len; i++)
+ pr_err("%s: msg[%03d] = 0x%08x", __func__, i, cmd[i]);
+ pr_err("%s: --------- cpp frame cmd msg end ---------", __func__);
+ return 0;
+}
+#else
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+ return 0;
+}
+#endif
+
static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
struct msm_queue_cmd *frame_qcmd)
{
@@ -927,6 +977,8 @@
msm_enqueue(&cpp_dev->processing_q,
&frame_qcmd->list_frame);
msm_cpp_write(0x6, cpp_dev->base);
+ msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
+ process_frame->msg_len);
for (i = 0; i < process_frame->msg_len; i++)
msm_cpp_write(process_frame->cpp_cmd_msg[i],
cpp_dev->base);
@@ -951,7 +1003,7 @@
struct msm_cpp_frame_info_t *new_frame =
kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
uint32_t *cpp_frame_msg;
- unsigned long in_phyaddr, out_phyaddr;
+ unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
uint16_t num_stripes = 0;
struct msm_buf_mngr_info buff_mgr_info;
struct msm_cpp_frame_info_t *u_frame_info =
@@ -1001,7 +1053,7 @@
goto ERROR2;
}
- memset(&new_frame->output_buffer_info, 0,
+ memset(&new_frame->output_buffer_info[0], 0,
sizeof(struct msm_cpp_buffer_info_t));
memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
@@ -1013,17 +1065,49 @@
pr_debug("error getting buffer rc:%d\n", rc);
goto ERROR2;
}
-
- new_frame->output_buffer_info.index = buff_mgr_info.index;
- out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
- &new_frame->output_buffer_info,
+ new_frame->output_buffer_info[0].index = buff_mgr_info.index;
+ out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev,
+ &new_frame->output_buffer_info[0],
((new_frame->identity >> 16) & 0xFFFF),
(new_frame->identity & 0xFFFF));
- if (!out_phyaddr) {
+ if (!out_phyaddr0) {
pr_err("error gettting output physical address\n");
rc = -EINVAL;
goto ERROR3;
}
+ out_phyaddr1 = out_phyaddr0;
+
+ /* get buffer for duplicate output */
+ if (new_frame->duplicate_output) {
+ CPP_DBG("duplication enabled, dup_id=0x%x",
+ new_frame->duplicate_identity);
+ memset(&new_frame->output_buffer_info[1], 0,
+ sizeof(struct msm_cpp_buffer_info_t));
+ memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id =
+ ((new_frame->duplicate_identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (new_frame->duplicate_identity & 0xFFFF);
+ rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+ &buff_mgr_info);
+ if (rc < 0) {
+ rc = -EAGAIN;
+ pr_err("error getting buffer rc:%d\n", rc);
+ goto ERROR2;
+ }
+ new_frame->output_buffer_info[1].index = buff_mgr_info.index;
+ out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
+ &new_frame->output_buffer_info[1],
+ ((new_frame->duplicate_identity >> 16) & 0xFFFF),
+ (new_frame->duplicate_identity & 0xFFFF));
+ if (!out_phyaddr1) {
+ pr_err("error gettting output physical address\n");
+ rc = -EINVAL;
+ goto ERROR3;
+ }
+ /* set duplicate enable bit */
+ cpp_frame_msg[5] |= 0x1;
+ }
num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
((cpp_frame_msg[12] >> 10) & 0x3FF) +
@@ -1031,10 +1115,10 @@
for (i = 0; i < num_stripes; i++) {
cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
- cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr;
- cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr;
- cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr;
- cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr;
+ cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr0;
+ cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr1;
+ cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr0;
+ cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr1;
}
frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
@@ -1245,6 +1329,13 @@
kfree(event_qcmd);
break;
}
+ case MSM_SD_SHUTDOWN: {
+ mutex_unlock(&cpp_dev->mutex);
+ while (cpp_dev->cpp_open_cnt != 0)
+ cpp_close_node(sd, NULL);
+ rc = 0;
+ break;
+ }
}
mutex_unlock(&cpp_dev->mutex);
CPP_DBG("X\n");
@@ -1446,6 +1537,7 @@
cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP;
cpp_dev->msm_sd.sd.entity.name = pdev->name;
+ cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY;
msm_sd_register(&cpp_dev->msm_sd);
msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index e1b978f..b115738 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -629,6 +629,9 @@
return msm_actuator_get_subdev_id(a_ctrl, argp);
case VIDIOC_MSM_ACTUATOR_CFG:
return msm_actuator_config(a_ctrl, argp);
+ case MSM_SD_SHUTDOWN:
+ msm_actuator_close(sd, NULL);
+ return 0;
default:
return -ENOIOCTLCMD;
}
@@ -710,6 +713,7 @@
media_entity_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL, 0);
act_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
act_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;
+ act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&act_ctrl_t->msm_sd);
CDBG("succeeded\n");
CDBG("Exit\n");
@@ -780,6 +784,7 @@
media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0);
msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;
+ msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&msm_actuator_t->msm_sd);
CDBG("Exit\n");
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 3409b3e..f3da41c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -773,6 +773,12 @@
case VIDIOC_MSM_CCI_CFG:
rc = msm_cci_config(sd, arg);
break;
+ case MSM_SD_SHUTDOWN: {
+ struct msm_camera_cci_ctrl ctrl_cmd;
+ ctrl_cmd.cmd = MSM_CCI_RELEASE;
+ rc = msm_cci_config(sd, &ctrl_cmd);
+ break;
+ }
default:
rc = -ENOIOCTLCMD;
}
@@ -1007,6 +1013,7 @@
goto cci_release_mem;
}
disable_irq(new_cci_dev->irq->start);
+ new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
msm_sd_register(&new_cci_dev->msm_sd);
new_cci_dev->pdev = pdev;
msm_cci_init_cci_params(new_cci_dev);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 33eaa69..4db6855 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -460,6 +460,7 @@
rc = msm_csid_cmd(csid_dev, arg);
break;
case VIDIOC_MSM_CSID_RELEASE:
+ case MSM_SD_SHUTDOWN:
rc = msm_csid_release(csid_dev);
break;
default:
@@ -552,6 +553,7 @@
media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0);
new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID;
+ new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5;
msm_sd_register(&new_csid_dev->msm_sd);
rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 7d3a1fc..429d151 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -570,6 +570,7 @@
rc = msm_csiphy_cmd(csiphy_dev, arg);
break;
case VIDIOC_MSM_CSIPHY_RELEASE:
+ case MSM_SD_SHUTDOWN:
rc = msm_csiphy_release(csiphy_dev, arg);
break;
default:
@@ -665,7 +666,7 @@
media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0);
new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY;
-
+ new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4;
msm_sd_register(&new_csiphy_dev->msm_sd);
new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
return 0;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index 9119a13..044fd31 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -81,6 +81,7 @@
media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0);
fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH;
+ fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
msm_sd_register(&fctrl->msm_sd);
CDBG("probe success\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index fa63e2b..28ade1a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -16,6 +16,9 @@
#include "msm_cci.h"
#include "msm_camera_io_util.h"
#include "msm_camera_i2c_mux.h"
+#include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
+#include <linux/regulator/consumer.h>
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
@@ -774,7 +777,17 @@
sensordata->slave_info->sensor_id_reg_addr = id_info[1];
sensordata->slave_info->sensor_id = id_info[2];
+ rc = of_property_read_string(of_node, "qcom,vdd-cx-name",
+ &sensordata->misc_regulator);
+ CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__,
+ sensordata->misc_regulator, rc);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR9;
+ }
+
kfree(gpio_array);
+
return rc;
ERROR9:
@@ -799,6 +812,41 @@
return rc;
}
+static void msm_sensor_misc_regulator(
+ struct msm_sensor_ctrl_t *sctrl, uint32_t enable)
+{
+ int32_t rc = 0;
+ if (enable) {
+ sctrl->misc_regulator = (void *)rpm_regulator_get(
+ &sctrl->pdev->dev, sctrl->sensordata->misc_regulator);
+ if (sctrl->misc_regulator) {
+ rc = rpm_regulator_set_mode(sctrl->misc_regulator,
+ RPM_REGULATOR_MODE_HPM);
+ if (rc < 0) {
+ pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+ __func__,
+ sctrl->sensordata->misc_regulator, rc);
+ rpm_regulator_put(sctrl->misc_regulator);
+ }
+ } else {
+ pr_err("%s: Failed to vote for rpm regulator on %s: %d\n",
+ __func__,
+ sctrl->sensordata->misc_regulator, rc);
+ }
+ } else {
+ if (sctrl->misc_regulator) {
+ rc = rpm_regulator_set_mode(
+ (struct rpm_regulator *)sctrl->misc_regulator,
+ RPM_REGULATOR_MODE_AUTO);
+ if (rc < 0)
+ pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+ __func__,
+ sctrl->sensordata->misc_regulator, rc);
+ rpm_regulator_put(sctrl->misc_regulator);
+ }
+ }
+}
+
int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
{
if (!s_ctrl->pdev)
@@ -814,6 +862,7 @@
kfree(s_ctrl->sensordata->sensor_info);
kfree(s_ctrl->sensordata->sensor_init_params);
kfree(s_ctrl->sensordata);
+ kfree(s_ctrl->clk_info);
return 0;
}
@@ -1001,6 +1050,7 @@
struct msm_sensor_power_setting_array *power_setting_array = NULL;
struct msm_sensor_power_setting *power_setting = NULL;
struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+ s_ctrl->stop_setting_valid = 0;
CDBG("%s:%d\n", __func__, __LINE__);
power_setting_array = &s_ctrl->power_setting_array;
@@ -1100,9 +1150,14 @@
static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
{
- s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
- s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
- kfree(s_ctrl->stop_setting.reg_setting);
+ mutex_lock(s_ctrl->msm_sensor_mutex);
+ if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+ s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+ s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
+ kfree(s_ctrl->stop_setting.reg_setting);
+ s_ctrl->stop_setting.reg_setting = NULL;
+ }
+ mutex_unlock(s_ctrl->msm_sensor_mutex);
return;
}
@@ -1119,6 +1174,7 @@
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
+ case MSM_SD_SHUTDOWN:
msm_sensor_stop_stream(s_ctrl);
return 0;
default:
@@ -1233,6 +1289,13 @@
struct msm_camera_i2c_reg_setting conf_array;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
+ rc = -EFAULT;
+ break;
+ }
+
if (copy_from_user(&conf_array,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_reg_setting))) {
@@ -1267,6 +1330,13 @@
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
+ rc = -EFAULT;
+ break;
+ }
+
if (copy_from_user(&conf_array,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_seq_reg_setting))) {
@@ -1301,18 +1371,56 @@
}
case CFG_POWER_UP:
- if (s_ctrl->func_tbl->sensor_power_up)
- rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
- else
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
+ break;
+ }
+ if (s_ctrl->func_tbl->sensor_power_up) {
+ if (s_ctrl->sensordata->misc_regulator)
+ msm_sensor_misc_regulator(s_ctrl, 1);
+
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+ if (rc < 0) {
+ pr_err("%s:%d failed rc %ld\n", __func__,
+ __LINE__, rc);
+ break;
+ }
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
+ pr_err("%s:%d sensor state %d\n", __func__, __LINE__,
+ s_ctrl->sensor_state);
+ } else {
+ rc = -EFAULT;
+ }
break;
case CFG_POWER_DOWN:
- if (s_ctrl->func_tbl->sensor_power_down)
+ kfree(s_ctrl->stop_setting.reg_setting);
+ s_ctrl->stop_setting.reg_setting = NULL;
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
+ rc = -EFAULT;
+ break;
+ }
+ if (s_ctrl->func_tbl->sensor_power_down) {
+ if (s_ctrl->sensordata->misc_regulator)
+ msm_sensor_misc_regulator(s_ctrl, 0);
+
rc = s_ctrl->func_tbl->sensor_power_down(
s_ctrl);
- else
+ if (rc < 0) {
+ pr_err("%s:%d failed rc %ld\n", __func__,
+ __LINE__, rc);
+ break;
+ }
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+ pr_err("%s:%d sensor state %d\n", __func__, __LINE__,
+ s_ctrl->sensor_state);
+ } else {
rc = -EFAULT;
+ }
break;
case CFG_SET_STOP_STREAM_SETTING: {
@@ -1326,6 +1434,7 @@
rc = -EFAULT;
break;
}
+ s_ctrl->stop_setting_valid = 1;
reg_setting = stop_setting->reg_setting;
stop_setting->reg_setting = kzalloc(stop_setting->size *
@@ -1363,8 +1472,10 @@
int rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
mutex_lock(s_ctrl->msm_sensor_mutex);
- if (!on)
- rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+ s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+ }
if (s_ctrl->free_power_setting == true) {
kfree(s_ctrl->power_setting_array.power_setting);
s_ctrl->free_power_setting = false;
@@ -1468,12 +1579,20 @@
&msm_sensor_cci_func_tbl;
if (!s_ctrl->sensor_v4l2_subdev_ops)
s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
- s_ctrl->clk_info = cam_8974_clk_info;
+ s_ctrl->clk_info = kzalloc(sizeof(cam_8974_clk_info),
+ GFP_KERNEL);
+ if (!s_ctrl->clk_info) {
+ pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+ kfree(cci_client);
+ return -ENOMEM;
+ }
+ memcpy(s_ctrl->clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info));
s_ctrl->clk_info_size = ARRAY_SIZE(cam_8974_clk_info);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
pr_err("%s %s power up failed\n", __func__,
s_ctrl->sensordata->sensor_name);
+ kfree(s_ctrl->clk_info);
kfree(cci_client);
return rc;
}
@@ -1496,6 +1615,7 @@
rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
s_ctrl->sensordata->sensor_info->session_id = session_id;
+ s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
msm_sd_register(&s_ctrl->msm_sd);
CDBG("%s:%d\n", __func__, __LINE__);
@@ -1554,12 +1674,19 @@
if (!s_ctrl->sensor_v4l2_subdev_ops)
s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
- s_ctrl->clk_info = cam_8960_clk_info;
+ s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
+ GFP_KERNEL);
+ if (!s_ctrl->clk_info) {
+ pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ memcpy(s_ctrl->clk_info, cam_8960_clk_info, sizeof(cam_8960_clk_info));
s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
pr_err("%s %s power up failed\n", __func__, client->name);
+ kfree(s_ctrl->clk_info);
return rc;
}
@@ -1580,6 +1707,7 @@
&session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
s_ctrl->sensordata->sensor_info->session_id = session_id;
+ s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
msm_sd_register(&s_ctrl->msm_sd);
CDBG("%s:%d\n", __func__, __LINE__);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index 6c36e47d..fe11a56 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -37,6 +37,11 @@
struct msm_sensor_ctrl_t;
+enum msm_sensor_state_t {
+ MSM_SENSOR_POWER_DOWN,
+ MSM_SENSOR_POWER_UP,
+};
+
struct msm_sensor_fn_t {
int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
int (*sensor_power_down)
@@ -62,9 +67,12 @@
struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
struct msm_sensor_fn_t *func_tbl;
struct msm_camera_i2c_reg_setting stop_setting;
+ bool stop_setting_valid;
bool free_power_setting;
struct msm_cam_clk_info *clk_info;
uint16_t clk_info_size;
+ void *misc_regulator;
+ enum msm_sensor_state_t sensor_state;
};
int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 5b385a0..d07387e 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4606,11 +4606,11 @@
mpq_demux->sdmx_filter_count, mpq_demux->filters_status);
process_end_time = current_kernel_time();
- mpq_dmx_update_sdmx_stat(mpq_demux, prev_fill_count,
- &process_start_time, &process_end_time);
-
bytes_read = prev_fill_count - fill_count;
+ mpq_dmx_update_sdmx_stat(mpq_demux, bytes_read,
+ &process_start_time, &process_end_time);
+
MPQ_DVB_DBG_PRINT(
"%s: SDMX result=%d, input_fill_count=%u, read_offset=%u, read %d bytes from input, status=0x%X, errors=0x%X\n",
__func__, sdmx_res, fill_count, read_offset, bytes_read,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 5e14d0c..a2ce428 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -54,14 +54,16 @@
#define TSPP_RAW_TTS_SIZE 192
#define TSPP_RAW_SIZE 188
-#define MAX_BAM_DESCRIPTOR_SIZE (32*1024 - 1)
+#define MAX_BAM_DESCRIPTOR_SIZE (32 * 1024 - 1)
+
+#define MAX_BAM_DESCRIPTOR_COUNT (8 * 1024 - 2)
#define TSPP_BUFFER_SIZE (500 * 1024) /* 500KB */
#define TSPP_DESCRIPTOR_SIZE (TSPP_RAW_TTS_SIZE)
#define TSPP_BUFFER_COUNT(buffer_size) \
- ((buffer_size) / TSPP_RAW_TTS_SIZE)
+ ((buffer_size) / TSPP_DESCRIPTOR_SIZE)
/* When TSPP notifies demux that new packets are received.
* Using max descriptor size (170 packets).
@@ -1799,6 +1801,11 @@
mpq_dmx_tspp_info.tsif[i].buffer_count =
TSPP_BUFFER_COUNT(tspp_out_buffer_size);
+ if (mpq_dmx_tspp_info.tsif[i].buffer_count >
+ MAX_BAM_DESCRIPTOR_COUNT)
+ mpq_dmx_tspp_info.tsif[i].buffer_count =
+ MAX_BAM_DESCRIPTOR_COUNT;
+
mpq_dmx_tspp_info.tsif[i].aggregate_ids =
vzalloc(mpq_dmx_tspp_info.tsif[i].buffer_count *
sizeof(int));
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 20cb08d..c3cfe76 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -787,11 +787,10 @@
if (*num_buffers > VIDEO_MAX_FRAME) {
dprintk(VIDC_ERR,
- "Failed : No of slices requested = %d"\
- " Max supported slices = %d",
- *num_buffers, VIDEO_MAX_FRAME);
- rc = -EINVAL;
- break;
+ "Changing buffers requested, from %d to max"\
+ " supported (%d) best effort encoding\n",
+ *num_buffers, VIDEO_MAX_FRAME);
+ *num_buffers = VIDEO_MAX_FRAME;
}
ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 123b654..577b2b5 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -362,17 +362,18 @@
void q6_hfi_delete_device(void *device)
{
- struct q6_hfi_device *close, *dev;
+ struct q6_hfi_device *close, *tmp, *dev;
if (device) {
q6_hfi_deinit_resources(device);
dev = (struct q6_hfi_device *) device;
- list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
if (close->device_id == dev->device_id) {
hal_ctxt.dev_count--;
list_del(&close->list);
destroy_workqueue(close->vidc_workq);
kfree(close);
+ break;
}
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 74733c2..bc5adc11 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2953,12 +2953,12 @@
void venus_hfi_delete_device(void *device)
{
- struct venus_hfi_device *close, *dev;
+ struct venus_hfi_device *close, *tmp, *dev;
if (device) {
venus_hfi_deinit_resources(device);
dev = (struct venus_hfi_device *) device;
- list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
if (close->hal_data->irq == dev->hal_data->irq) {
hal_ctxt.dev_count--;
free_irq(dev->hal_data->irq, close);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 0c5534c..ea7032b 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1001,9 +1001,15 @@
FMDBG("Search list has %d stations\n",
radio->registers[XFRCTRL+1]);
radio->xfr_bytes_left = radio->registers[XFRCTRL+1]*2;
- if (radio->xfr_bytes_left > 14) {
+ if (!radio->registers[XFRCTRL+1]) {
copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
- XFR_REG_NUM);
+ 1);
+ tavarua_q_event(radio,
+ TAVARUA_EVT_NEW_SRCH_LIST);
+ radio->xfr_in_progress = 0;
+ } else if (radio->xfr_bytes_left > 14) {
+ copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
+ RX_STATIONS0_LEN);
request_read_xfr(radio, RX_STATIONS_1);
} else if (radio->xfr_bytes_left) {
FMDBG("In else RX_STATIONS_0\n");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index fa28d6a..c60537a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -45,7 +45,6 @@
#include "qseecom_kernel.h"
#define QSEECOM_DEV "qseecom"
-#define QSEOS_VERSION_13 0x13
#define QSEOS_VERSION_14 0x14
#define QSEEE_VERSION_00 0x400000
#define QSEE_VERSION_01 0x401000
@@ -90,11 +89,6 @@
static dev_t qseecom_device_no;
static struct cdev qseecom_cdev;
-/* Data structures used in legacy support */
-static void *pil;
-static uint32_t pil_ref_cnt;
-static DEFINE_MUTEX(pil_access_lock);
-
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
@@ -278,63 +272,24 @@
svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
svc->sb_phys = pa;
- if (qseecom.qseos_version == QSEOS_VERSION_14) {
- req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
- req.listener_id = svc->svc.listener_id;
- req.sb_len = svc->sb_length;
- req.sb_ptr = (void *)svc->sb_phys;
+ req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
+ req.listener_id = svc->svc.listener_id;
+ req.sb_len = svc->sb_length;
+ req.sb_ptr = (void *)svc->sb_phys;
- resp.result = QSEOS_RESULT_INCOMPLETE;
+ resp.result = QSEOS_RESULT_INCOMPLETE;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return -EINVAL;
- }
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return -EINVAL;
+ }
- if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("Error SB registration req: resp.result = %d\n",
- resp.result);
- return -EPERM;
- }
- } else {
- struct qseecom_command cmd;
- struct qseecom_response resp;
- struct qse_pr_init_sb_req_s sb_init_req;
- struct qse_pr_init_sb_rsp_s sb_init_rsp;
-
- svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
- sizeof(sb_init_rsp)), GFP_KERNEL);
-
- sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
- sb_init_req.listener_id = svc->svc.listener_id;
- sb_init_req.sb_len = svc->sb_length;
- sb_init_req.sb_ptr = svc->sb_phys;
-
- memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
-
- /* It will always be a new cmd from this method */
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
- cmd.sb_in_cmd_len = sizeof(sb_init_req);
-
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
- , &resp, sizeof(resp));
-
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return -EINVAL;
- }
-
- if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- pr_err("SB registration fail resp.cmd_status %d\n",
- resp.cmd_status);
- return -EINVAL;
- }
- memset(svc->sb_virt, 0, svc->sb_length);
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("Error SB registration req: resp.result = %d\n",
+ resp.result);
+ return -EPERM;
}
return 0;
}
@@ -396,56 +351,24 @@
struct qseecom_command_scm_resp resp;
struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
- if (qseecom.qseos_version == QSEOS_VERSION_14) {
- req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
- req.listener_id = data->listener.id;
- resp.result = QSEOS_RESULT_INCOMPLETE;
+ req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
+ req.listener_id = data->listener.id;
+ resp.result = QSEOS_RESULT_INCOMPLETE;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
- if (ret) {
- pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
- ret, data->listener.id);
- return ret;
- }
-
- if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
- resp.result, data->listener.id);
- return -EPERM;
- }
- } else {
- struct qse_pr_init_sb_req_s sb_init_req;
- struct qseecom_command cmd;
- struct qseecom_response resp;
- struct qseecom_registered_listener_list *svc;
-
- svc = __qseecom_find_svc(data->listener.id);
- sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
- sb_init_req.listener_id = data->listener.id;
- sb_init_req.sb_len = 0;
- sb_init_req.sb_ptr = 0;
-
- memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
-
- /* It will always be a new cmd from this method */
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
- cmd.sb_in_cmd_len = sizeof(sb_init_req);
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
- &resp, sizeof(resp));
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return ret;
- }
- kzfree(svc->sb_reg_req);
- if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- pr_err("Error with SB initialization\n");
- return -EPERM;
- }
+ if (ret) {
+ pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
+ ret, data->listener.id);
+ return ret;
}
+
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
+ resp.result, data->listener.id);
+ return -EPERM;
+ }
+
data->abort = 1;
spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
@@ -540,6 +463,8 @@
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
struct qseecom_registered_listener_list *ptr_svc = NULL;
+ sigset_t new_sigset;
+ sigset_t old_sigset;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -564,17 +489,24 @@
}
pr_debug("waking up rcv_req_wq and "
"waiting for send_resp_wq\n");
- if (wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- pr_warning("Interrupted: exiting send_cmd loop\n");
- ret = -ERESTARTSYS;
- }
- if ((data->abort) || (ret == -ERESTARTSYS)) {
+ /* initialize the new signal mask with all signals*/
+ sigfillset(&new_sigset);
+ /* block all signals */
+ sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+ do {
+ if (!wait_event_freezable(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(data)))
+ break;
+ } while (1);
+
+ /* restore signal mask */
+ sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+ if (data->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
- if (data->abort)
- rc = -ENODEV;
+ rc = -ENODEV;
send_data_rsp.status = QSEOS_RESULT_FAILURE;
} else {
send_data_rsp.status = QSEOS_RESULT_SUCCESS;
@@ -821,8 +753,7 @@
bool unload = false;
bool found_app = false;
- if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
- (data->client.app_id > 0)) {
+ if (data->client.app_id > 0) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
list) {
@@ -848,7 +779,7 @@
}
}
- if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
+ if (unload) {
struct qseecom_unload_app_ireq req;
__qseecom_cleanup_app(data);
@@ -881,19 +812,6 @@
}
}
}
-
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- data->abort = 1;
- wake_up_all(&qseecom.send_resp_wq);
- while (atomic_read(&data->ioctl_count) > 0) {
- if (wait_event_freezable(data->abort_wq,
- atomic_read(&data->ioctl_count) <= 0)) {
- pr_err("Interrupted from abort\n");
- ret = -ERESTARTSYS;
- break;
- }
- }
- }
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
@@ -905,98 +823,6 @@
return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
}
-static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
- struct qseecom_send_cmd_req *req)
-{
- int ret = 0;
- unsigned long flags;
- u32 reqd_len_sb_in = 0;
- struct qseecom_command cmd;
- struct qseecom_response resp;
-
-
- if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
- pr_err("cmd buffer or response buffer is null\n");
- return -EINVAL;
- }
-
- if (req->cmd_req_len <= 0 ||
- req->resp_len <= 0 ||
- req->cmd_req_len > data->client.sb_length ||
- req->resp_len > data->client.sb_length) {
- pr_err("cmd buffer length or "
- "response buffer length not valid\n");
- return -EINVAL;
- }
-
- reqd_len_sb_in = req->cmd_req_len + req->resp_len;
- if (reqd_len_sb_in > data->client.sb_length) {
- pr_debug("Not enough memory to fit cmd_buf and "
- "resp_buf. Required: %u, Available: %u\n",
- reqd_len_sb_in, data->client.sb_length);
- return -ENOMEM;
- }
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
- cmd.sb_in_cmd_len = req->cmd_req_len;
-
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
- resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
- resp.sb_in_rsp_len = req->resp_len;
-
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
- sizeof(cmd), &resp, sizeof(resp));
-
- if (ret) {
- pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
- return ret;
- }
-
- while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- /*
- * If cmd is incomplete, get the callback cmd out from SB out
- * and put it on the list
- */
- struct qseecom_registered_listener_list *ptr_svc = NULL;
- /*
- * We don't know which service can handle the command. so we
- * wake up all blocking services and let them figure out if
- * they can handle the given command.
- */
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
- list_for_each_entry(ptr_svc,
- &qseecom.registered_listener_list_head, list) {
- ptr_svc->rcv_req_flag = 1;
- wake_up_interruptible(&ptr_svc->rcv_req_wq);
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
-
- pr_debug("waking up rcv_req_wq and "
- "waiting for send_resp_wq\n");
- if (wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
- return -ERESTARTSYS;
- }
-
- if (data->abort) {
- pr_err("Aborting driver\n");
- return -ENODEV;
- }
- qseecom.send_resp_flag = 0;
- cmd.cmd_type = TZ_SCHED_CMD_PENDING;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
- sizeof(cmd), &resp, sizeof(resp));
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return ret;
- }
- }
- return ret;
-}
-
int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
struct qseecom_send_svc_cmd_req *req_ptr,
struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
@@ -1162,10 +988,8 @@
pr_err("copy_from_user failed\n");
return ret;
}
- if (qseecom.qseos_version == QSEOS_VERSION_14)
- ret = __qseecom_send_cmd(data, &req);
- else
- ret = __qseecom_send_cmd_legacy(data, &req);
+ ret = __qseecom_send_cmd(data, &req);
+
if (ret)
return ret;
@@ -1174,27 +998,8 @@
return ret;
}
-static int __qseecom_send_cmd_req_clean_up(
- struct qseecom_send_modfd_cmd_req *req)
-{
- char *field;
- uint32_t *update;
- int ret = 0;
- int i = 0;
-
- for (i = 0; i < MAX_ION_FD; i++) {
- if (req->ifd_data[i].fd > 0) {
- field = (char *)req->cmd_req_buf +
- req->ifd_data[i].cmd_buf_offset;
- update = (uint32_t *) field;
- *update = 0;
- }
- }
- return ret;
-}
-
-static int __qseecom_update_with_phy_addr(
- struct qseecom_send_modfd_cmd_req *req)
+static int __qseecom_update_cmd_buf(struct qseecom_send_modfd_cmd_req *req,
+ bool cleanup)
{
struct ion_handle *ihandle;
char *field;
@@ -1233,7 +1038,11 @@
if (sg_ptr->nents == 1) {
uint32_t *update;
update = (uint32_t *) field;
- *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
+ if (cleanup)
+ *update = 0;
+ else
+ *update = (uint32_t)sg_dma_address(
+ sg_ptr->sgl);
} else {
struct qseecom_sg_entry *update;
struct scatterlist *sg;
@@ -1241,9 +1050,14 @@
update = (struct qseecom_sg_entry *) field;
sg = sg_ptr->sgl;
for (j = 0; j < sg_ptr->nents; j++) {
- update->phys_addr = (uint32_t)
- sg_dma_address(sg);
- update->len = (uint32_t)sg->length;
+ if (cleanup) {
+ update->phys_addr = 0;
+ update->len = 0;
+ } else {
+ update->phys_addr = (uint32_t)
+ sg_dma_address(sg);
+ update->len = sg->length;
+ }
update++;
sg = sg_next(sg);
}
@@ -1277,18 +1091,15 @@
send_cmd_req.resp_buf = req.resp_buf;
send_cmd_req.resp_len = req.resp_len;
- ret = __qseecom_update_with_phy_addr(&req);
+ ret = __qseecom_update_cmd_buf(&req, false);
if (ret)
return ret;
- if (qseecom.qseos_version == QSEOS_VERSION_14)
- ret = __qseecom_send_cmd(data, &send_cmd_req);
- else
- ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
- __qseecom_send_cmd_req_clean_up(&req);
-
+ ret = __qseecom_send_cmd(data, &send_cmd_req);
if (ret)
return ret;
-
+ ret = __qseecom_update_cmd_buf(&req, true);
+ if (ret)
+ return ret;
pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
req.resp_len, req.resp_buf);
return ret;
@@ -1324,12 +1135,7 @@
return -ENODEV;
}
this_lstnr->rcv_req_flag = 0;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- if (*((uint32_t *)this_lstnr->sb_virt) != 0)
- break;
- } else {
- break;
- }
+ break;
}
return ret;
}
@@ -1627,11 +1433,6 @@
uint32_t len;
ion_phys_addr_t pa;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("This functionality is UNSUPPORTED in version 1.3\n");
- return -EINVAL;
- }
-
*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
if (!(*handle)) {
pr_err("failed to allocate memory for kernel client handle\n");
@@ -1666,34 +1467,26 @@
*handle = NULL;
return -EINVAL;
}
-
+ mutex_lock(&app_access_lock);
if (qseecom.qsee_version > QSEEE_VERSION_00) {
- mutex_lock(&app_access_lock);
if (qseecom.commonlib_loaded == false) {
ret = qseecom_load_commonlib_image(data);
if (ret == 0)
qseecom.commonlib_loaded = true;
}
- mutex_unlock(&app_access_lock);
}
-
if (ret) {
pr_err("Failed to load commonlib image\n");
- kfree(data);
- kfree(*handle);
- *handle = NULL;
- return -EIO;
+ ret = -EIO;
+ goto err;
}
app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(app_ireq);
- if (ret < 0) {
- kzfree(data);
- kfree(*handle);
- *handle = NULL;
- return -EINVAL;
- }
+ if (ret < 0)
+ goto err;
+
data->client.app_id = ret;
if (ret > 0) {
pr_warn("App id %d for [%s] app exists\n", ret,
@@ -1716,26 +1509,17 @@
/* load the app and get the app_id */
pr_debug("%s: Loading app for the first time'\n",
qseecom.pdev->init_name);
- mutex_lock(&app_access_lock);
ret = __qseecom_load_fw(data, app_name);
- mutex_unlock(&app_access_lock);
-
- if (ret < 0) {
- kfree(*handle);
- kfree(data);
- *handle = NULL;
- return ret;
- }
+ if (ret < 0)
+ goto err;
data->client.app_id = ret;
}
if (!found_app) {
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
- pr_err("kmalloc failed\n");
- kfree(data);
- kfree(*handle);
- *handle = NULL;
- return -ENOMEM;
+ pr_err("kmalloc for app entry failed\n");
+ ret = -ENOMEM;
+ goto err;
}
entry->app_id = ret;
entry->ref_cnt = 1;
@@ -1760,7 +1544,8 @@
kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
if (!kclient_entry) {
pr_err("kmalloc failed\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
kclient_entry->handle = *handle;
@@ -1769,7 +1554,15 @@
&qseecom.registered_kclient_list_head);
spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+ mutex_unlock(&app_access_lock);
return 0;
+
+err:
+ kfree(data);
+ kfree(*handle);
+ *handle = NULL;
+ mutex_unlock(&app_access_lock);
+ return ret;
}
EXPORT_SYMBOL(qseecom_start_app);
@@ -1782,10 +1575,6 @@
unsigned long flags = 0;
bool found_handle = false;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("This functionality is UNSUPPORTED in version 1.3\n");
- return -EINVAL;
- }
if ((handle == NULL) || (*handle == NULL)) {
pr_err("Handle is not initialized\n");
return -EINVAL;
@@ -1826,11 +1615,6 @@
struct qseecom_send_cmd_req req = {0, 0, 0, 0};
struct qseecom_dev_handle *data;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("This functionality is UNSUPPORTED in version 1.3\n");
- return -EINVAL;
- }
-
if (handle == NULL) {
pr_err("Handle is not initialized\n");
return -EINVAL;
@@ -2410,12 +2194,13 @@
case QSEOS_RESULT_SUCCESS:
break;
case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
+ pr_debug("process_incomplete_cmd return Key ID exists.\n");
break;
case QSEOS_RESULT_INCOMPLETE:
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
- pr_warn("process_incomplete_cmd return Key ID exits.\n");
+ pr_debug("process_incomplete_cmd return Key ID exists.\n");
ret = 0;
} else {
pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
@@ -2494,9 +2279,8 @@
return -EFAULT;
}
- if (qseecom.qsee.instance == qseecom.ce_drv.instance)
- __qseecom_enable_clk(CLK_QSEE);
- else
+ __qseecom_enable_clk(CLK_QSEE);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance)
__qseecom_enable_clk(CLK_CE_DRV);
memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
@@ -2520,6 +2304,9 @@
&resp, sizeof(struct qseecom_command_scm_resp));
if (ret) {
pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
+ __qseecom_disable_clk(CLK_QSEE);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance)
+ __qseecom_disable_clk(CLK_CE_DRV);
return ret;
}
@@ -2539,9 +2326,8 @@
break;
}
- if (qseecom.qsee.instance == qseecom.ce_drv.instance)
- __qseecom_disable_clk(CLK_QSEE);
- else
+ __qseecom_disable_clk(CLK_QSEE);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance)
__qseecom_disable_clk(CLK_CE_DRV);
return ret;
@@ -2857,11 +2643,6 @@
}
case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
data->released = true;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("Loading External elf image unsupported in rev 0x13\n");
- ret = -EINVAL;
- break;
- }
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_load_external_elf(data, argp);
@@ -2873,11 +2654,6 @@
}
case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
data->released = true;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("Unloading External elf image unsupported in rev 0x13\n");
- ret = -EINVAL;
- break;
- }
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_unload_external_elf(data);
@@ -2981,23 +2757,7 @@
data->released = false;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- int pil_error;
- mutex_lock(&pil_access_lock);
- if (pil_ref_cnt == 0) {
- pil = subsystem_get("tzapps");
- if (IS_ERR(pil)) {
- pr_err("Playready PIL image load failed\n");
- pil_error = PTR_ERR(pil);
- pil = NULL;
- pr_debug("tzapps image load FAILED\n");
- mutex_unlock(&pil_access_lock);
- return pil_error;
- }
- }
- pil_ref_cnt++;
- mutex_unlock(&pil_access_lock);
- }
+
return ret;
}
@@ -3035,13 +2795,6 @@
if (data->perf_enabled == true)
qsee_disable_clock_vote(data, CLK_DFAB);
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- mutex_lock(&pil_access_lock);
- if (pil_ref_cnt == 1)
- subsystem_put(pil);
- pil_ref_cnt--;
- mutex_unlock(&pil_access_lock);
- }
kfree(data);
return ret;
@@ -3246,10 +2999,10 @@
}
qseecom.qseos_version = QSEOS_VERSION_14;
} else {
- qseecom.qseos_version = QSEOS_VERSION_13;
- qseecom.qsee_version = 0;
- pil = NULL;
- pil_ref_cnt = 0;
+ pr_err("QSEE legacy version is not supported:");
+ pr_err("Support for TZ1.3 and earlier is deprecated\n");
+ rc = -EINVAL;
+ goto err;
}
qseecom.commonlib_loaded = false;
qseecom.pdev = class_dev;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 501da4c8..e0fffbd 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -62,9 +62,8 @@
/*
* BAM descriptor FIFO size (in number of descriptors).
* Max number of descriptors allowed by SPS which is 8K-1.
- * Restrict it to half of this to save DMA memory.
*/
-#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
+#define TSPP_SPS_DESCRIPTOR_COUNT (8 * 1024 - 1)
#define TSPP_PACKET_LENGTH 188
#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
@@ -2236,6 +2235,12 @@
return -EINVAL;
}
+ if (count > TSPP_NUM_BUFFERS) {
+ pr_err("%s: tspp requires a maximum of %i buffers\n",
+ __func__, TSPP_NUM_BUFFERS);
+ return -EINVAL;
+ }
+
channel = &pdev->channels[channel_id];
/* allow buffer allocation only if there was no previous buffer
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 89730b0..d850782 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2137,7 +2137,7 @@
int ret = 0, dead = 0;
u32 vdd_max_current;
u16 host_version;
- u32 pwr;
+ u32 pwr, irq_status, irq_ctl;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2265,6 +2265,27 @@
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
/*
+ * CORE_SW_RST above may trigger power irq if previous status of PWRCTL
+ * was either BUS_ON or IO_HIGH_V. So before we enable the power irq
+ * interrupt in GIC (by registering the interrupt handler), we need to
+ * ensure that any pending power irq interrupt status is acknowledged
+ * otherwise power irq interrupt handler would be fired prematurely.
+ */
+ irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+ writel_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+ irq_ctl = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL);
+ if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+ irq_ctl |= CORE_PWRCTL_BUS_SUCCESS;
+ if (irq_status & (CORE_PWRCTL_IO_HIGH | CORE_PWRCTL_IO_LOW))
+ irq_ctl |= CORE_PWRCTL_IO_SUCCESS;
+ writel_relaxed(irq_ctl, (msm_host->core_mem + CORE_PWRCTL_CTL));
+ /*
+ * Ensure that above writes are propogated before interrupt enablement
+ * in GIC.
+ */
+ mb();
+
+ /*
* Following are the deviations from SDHC spec v3.0 -
* 1. Card detection is handled using separate GPIO.
* 2. Bus power control is handled by interacting with PMIC.
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3efea77..4f9bbad 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -51,6 +51,7 @@
static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static void sdhci_tuning_timer(unsigned long data);
+static bool sdhci_check_state(struct sdhci_host *);
#ifdef CONFIG_PM_RUNTIME
static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -292,7 +293,7 @@
spin_lock_irqsave(&host->lock, flags);
- if (host->runtime_suspended)
+ if (host->runtime_suspended || sdhci_check_state(host))
goto out;
if (brightness == LED_OFF)
@@ -1395,7 +1396,8 @@
struct mmc_host *mmc = host->mmc;
if (!host->clock || !host->pwr ||
- pm_runtime_suspended(mmc->parent))
+ (mmc_use_core_runtime_pm(mmc) ?
+ pm_runtime_suspended(mmc->parent) : 0))
return true;
else
return false;
@@ -2887,6 +2889,8 @@
host = mmc_priv(mmc);
host->mmc = mmc;
+ spin_lock_init(&host->lock);
+
return host;
}
@@ -3232,8 +3236,6 @@
return -ENODEV;
}
- spin_lock_init(&host->lock);
-
/*
* Maximum number of segments. Depends on if the hardware
* can do scatter/gather or not.
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 59a6b68..c02daa4 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -31,6 +31,7 @@
static LIST_HEAD(power_on_lock_list);
static DEFINE_MUTEX(list_lock);
static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+static int auto_detect;
#define MSM_RIVA_PHYS 0x03204000
#define MSM_PRONTO_PHYS 0xfb21b000
@@ -42,11 +43,17 @@
#define PRONTO_SPARE_OFFSET 0x1088
#define NVBIN_DLND_BIT BIT(25)
+#define PRONTO_IRIS_REG_READ_OFFSET 0x1134
+#define PRONTO_IRIS_REG_CHIP_ID 0x04
+
#define WCNSS_PMU_CFG_IRIS_XO_CFG BIT(3)
#define WCNSS_PMU_CFG_IRIS_XO_EN BIT(4)
#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5)
#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
+#define WCNSS_PMU_CFG_IRIS_XO_READ BIT(9)
+#define WCNSS_PMU_CFG_IRIS_XO_READ_STS BIT(10)
+
#define WCNSS_PMU_CFG_IRIS_XO_MODE 0x6
#define WCNSS_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
@@ -56,6 +63,8 @@
#define VREG_OPTIMUM_MODE_MASK 0x0004
#define VREG_ENABLE_MASK 0x0008
+#define WCNSS_INVALID_IRIS_REG 0xbaadbaad
+
struct vregs_info {
const char * const name;
int state;
@@ -110,10 +119,38 @@
struct list_head list;
};
+enum {
+ WCNSS_XO_48MHZ = 1,
+ WCNSS_XO_19MHZ,
+ WCNSS_XO_INVALID,
+};
+
+enum {
+ IRIS_3660, /* also 3660A and 3680 */
+ IRIS_3620
+};
+
+
+int xo_auto_detect(u32 reg)
+{
+ reg >>= 30;
+
+ switch (reg) {
+ case IRIS_3660:
+ return WCNSS_XO_48MHZ;
+
+ case IRIS_3620:
+ return WCNSS_XO_19MHZ;
+
+ default:
+ return WCNSS_XO_INVALID;
+ }
+}
static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
{
u32 reg = 0;
+ u32 iris_reg = WCNSS_INVALID_IRIS_REG;
int rc = 0;
int size = 0;
int pmu_offset = 0;
@@ -121,6 +158,7 @@
unsigned long wcnss_phys_addr;
void __iomem *pmu_conf_reg;
void __iomem *spare_reg;
+ void __iomem *iris_read_reg;
struct clk *clk;
struct clk *clk_rf = NULL;
@@ -136,14 +174,6 @@
return PTR_ERR(clk);
}
- if (!use_48mhz_xo) {
- clk_rf = clk_get(dev, "rf_clk");
- if (IS_ERR(clk_rf)) {
- pr_err("Couldn't get rf_clk\n");
- clk_put(clk);
- return PTR_ERR(clk_rf);
- }
- }
} else {
wcnss_phys_addr = MSM_RIVA_PHYS;
pmu_offset = RIVA_PMU_OFFSET;
@@ -187,10 +217,44 @@
WCNSS_PMU_CFG_IRIS_XO_EN;
writel_relaxed(reg, pmu_conf_reg);
+ if (wcnss_xo_auto_detect_enabled()) {
+ iris_read_reg = msm_wcnss_base +
+ PRONTO_IRIS_REG_READ_OFFSET;
+ iris_reg = readl_relaxed(iris_read_reg);
+ }
+
+ if (iris_reg != WCNSS_INVALID_IRIS_REG) {
+ iris_reg &= 0xffff;
+ iris_reg |= PRONTO_IRIS_REG_CHIP_ID;
+ writel_relaxed(iris_reg, iris_read_reg);
+
+ /* Iris read */
+ reg = readl_relaxed(pmu_conf_reg);
+ reg |= WCNSS_PMU_CFG_IRIS_XO_READ;
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Wait for PMU_CFG.iris_reg_read_sts */
+ while (readl_relaxed(pmu_conf_reg) &
+ WCNSS_PMU_CFG_IRIS_XO_READ_STS)
+ cpu_relax();
+
+ iris_reg = readl_relaxed(iris_read_reg);
+ auto_detect = xo_auto_detect(iris_reg);
+
+ /* Reset iris read bit */
+ reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
+
+ } else if (wcnss_xo_auto_detect_enabled())
+ /* Default to 48 MHZ */
+ auto_detect = WCNSS_XO_48MHZ;
+ else
+ auto_detect = WCNSS_XO_INVALID;
+
/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
- if (use_48mhz_xo)
+ if ((use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+ || auto_detect == WCNSS_XO_48MHZ)
reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
writel_relaxed(reg, pmu_conf_reg);
@@ -210,30 +274,41 @@
writel_relaxed(reg, pmu_conf_reg);
clk_disable_unprepare(clk);
- if (!use_48mhz_xo) {
+ if ((!use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+ || auto_detect == WCNSS_XO_19MHZ) {
+
+ clk_rf = clk_get(dev, "rf_clk");
+ if (IS_ERR(clk_rf)) {
+ pr_err("Couldn't get rf_clk\n");
+ goto fail;
+ }
+
rc = clk_prepare_enable(clk_rf);
if (rc) {
pr_err("clk_rf enable failed\n");
goto fail;
}
}
- } else if (clk_rf != NULL && !use_48mhz_xo)
- clk_disable_unprepare(clk_rf);
+
+ } else if ((!use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+ || auto_detect == WCNSS_XO_19MHZ) {
+ clk_rf = clk_get(dev, "rf_clk");
+ if (IS_ERR(clk_rf)) {
+ pr_err("Couldn't get rf_clk\n");
+ goto fail;
+ }
+ clk_disable_unprepare(clk_rf);
+ }
+
/* Add some delay for XO to settle */
msleep(20);
+fail:
clk_put(clk);
- if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
- if (!use_48mhz_xo)
- clk_put(clk_rf);
- }
-
- return rc;
-fail:
if (clk_rf != NULL)
clk_put(clk_rf);
- clk_put(clk);
+
return rc;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index f837a06..a75687b 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -31,6 +31,7 @@
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
+#include <linux/mfd/pm8xxx/misc.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
@@ -55,6 +56,10 @@
module_param(has_calibrated_data, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_calibrated_data, "whether calibrated data file available");
+static int has_autodetect_xo = WCNSS_CONFIG_UNSPECIFIED;
+module_param(has_autodetect_xo, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(has_autodetect_xo, "Perform auto detect to configure IRIS XO");
+
static int do_not_cancel_vote = WCNSS_CONFIG_UNSPECIFIED;
module_param(do_not_cancel_vote, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(do_not_cancel_vote, "Do not cancel votes for wcnss");
@@ -133,6 +138,21 @@
unsigned char revision;
};
+struct wcnss_pmic_dump {
+ char reg_name[10];
+ u16 reg_addr;
+};
+
+static struct wcnss_pmic_dump wcnss_pmic_reg_dump[] = {
+ {"S2", 0x1D8},
+ {"L4", 0xB4},
+ {"L10", 0xC0},
+ {"LVS2", 0x62},
+ {"S4", 0x1E8},
+ {"LVS7", 0x06C},
+ {"LVS1", 0x060},
+};
+
#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
/*
@@ -342,6 +362,25 @@
static DEVICE_ATTR(wcnss_version, S_IRUSR,
wcnss_version_show, NULL);
+void wcnss_riva_dump_pmic_regs(void)
+{
+ int i, rc;
+ u8 val;
+
+ for (i = 0; i < ARRAY_SIZE(wcnss_pmic_reg_dump); i++) {
+ val = 0;
+ rc = pm8xxx_read_register(wcnss_pmic_reg_dump[i].reg_addr,
+ &val);
+ if (rc)
+ pr_err("PMIC READ: Failed to read addr = %d\n",
+ wcnss_pmic_reg_dump[i].reg_addr);
+ else
+ pr_info_ratelimited("PMIC READ: %s addr = %x, value = %x\n",
+ wcnss_pmic_reg_dump[i].reg_name,
+ wcnss_pmic_reg_dump[i].reg_addr, val);
+ }
+}
+
/* wcnss_reset_intr() is invoked when host drivers fails to
* communicate with WCNSS over SMD; so logging these registers
* helps to know WCNSS failure reason
@@ -366,6 +405,7 @@
ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+ wcnss_riva_dump_pmic_regs();
}
EXPORT_SYMBOL(wcnss_riva_log_debug_regs);
@@ -837,6 +877,11 @@
module_param_call(enable_wcnss_suspend_notify, enable_wcnss_suspend_notify_set,
param_get_int, &enable_wcnss_suspend_notify, S_IRUGO | S_IWUSR);
+int wcnss_xo_auto_detect_enabled(void)
+{
+ return (has_autodetect_xo == 1 ? 1 : 0);
+}
+
void wcnss_suspend_notify(void)
{
@@ -1471,6 +1516,11 @@
penv->wcnss_hw_type = (has_pronto_hw) ? WCNSS_PRONTO_HW : WCNSS_RIVA_HW;
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
+ if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
+ has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has_autodetect_xo");
+ }
+
penv->thermal_mitigation = 0;
strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index fe151b5..acd42ae3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -107,4 +107,10 @@
help
OpenFirmware SLIMBUS accessors
+config OF_CORESIGHT
+ def_bool y
+ depends on CORESIGHT
+ help
+ OpenFirmware CoreSight accessors
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index c3a31c8..61a99f2 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -15,3 +15,4 @@
obj-$(CONFIG_OF_SPMI) += of_spmi.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_SLIMBUS) += of_slimbus.o
+obj-$(CONFIG_OF_CORESIGHT) += of_coresight.o
diff --git a/drivers/coresight/of_coresight.c b/drivers/of/of_coresight.c
similarity index 100%
rename from drivers/coresight/of_coresight.c
rename to drivers/of/of_coresight.c
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index fa71efc..0d77741 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -536,6 +536,8 @@
__func__);
return -EFAULT;
}
+ if (sps_ctrl_bam_dma_clk(true))
+ WARN_ON(1);
memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
connect_params.client = IPA_CLIENT_A2_TETHERED_CONS;
connect_params.notify = ipa_tethered_notify;
@@ -606,6 +608,8 @@
ipa_bridge_teardown(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
a2_mux_ctx->tethered_prod);
bridge_tethered_ul_failed:
+ if (sps_ctrl_bam_dma_clk(false))
+ WARN_ON(1);
return ret;
}
@@ -647,6 +651,8 @@
__func__, ret);
return ret;
}
+ if (sps_ctrl_bam_dma_clk(false))
+ WARN_ON(1);
verify_tx_queue_is_empty(__func__);
(void) ipa_rm_release_resource(IPA_RM_RESOURCE_A2_PROD);
if (a2_mux_ctx->disconnect_ack)
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 35b2561..6495db4 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1738,22 +1738,6 @@
result = -ENOMEM;
goto fail_rt_tbl_cache;
}
- ipa_ctx->tx_pkt_wrapper_cache =
- kmem_cache_create("IPA TX PKT WRAPPER",
- sizeof(struct ipa_tx_pkt_wrapper), 0, 0, NULL);
- if (!ipa_ctx->tx_pkt_wrapper_cache) {
- IPAERR(":ipa tx pkt wrapper cache create failed\n");
- result = -ENOMEM;
- goto fail_tx_pkt_wrapper_cache;
- }
- ipa_ctx->rx_pkt_wrapper_cache =
- kmem_cache_create("IPA RX PKT WRAPPER",
- sizeof(struct ipa_rx_pkt_wrapper), 0, 0, NULL);
- if (!ipa_ctx->rx_pkt_wrapper_cache) {
- IPAERR(":ipa rx pkt wrapper cache create failed\n");
- result = -ENOMEM;
- goto fail_rx_pkt_wrapper_cache;
- }
ipa_ctx->tree_node_cache =
kmem_cache_create("IPA TREE", sizeof(struct ipa_tree_node), 0, 0,
NULL);
@@ -1822,6 +1806,8 @@
mutex_init(&ipa_ctx->lock);
mutex_init(&ipa_ctx->nat_mem.lock);
+ skb_queue_head_init(&ipa_ctx->rx_list);
+
for (i = 0; i < IPA_A5_SYS_MAX; i++) {
INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
spin_lock_init(&ipa_ctx->sys[i].spinlock);
@@ -1835,15 +1821,15 @@
atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
}
- ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
+ ipa_ctx->rx_wq = alloc_workqueue("ipa rx wq", WQ_MEM_RECLAIM |
+ WQ_CPU_INTENSIVE, 1);
if (!ipa_ctx->rx_wq) {
IPAERR(":fail to create rx wq\n");
result = -ENOMEM;
goto fail_rx_wq;
}
- ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
- WQ_CPU_INTENSIVE, 2);
+ ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
if (!ipa_ctx->tx_wq) {
IPAERR(":fail to create tx wq\n");
result = -ENOMEM;
@@ -1996,10 +1982,6 @@
fail_dma_pool:
kmem_cache_destroy(ipa_ctx->tree_node_cache);
fail_tree_node_cache:
- kmem_cache_destroy(ipa_ctx->rx_pkt_wrapper_cache);
-fail_rx_pkt_wrapper_cache:
- kmem_cache_destroy(ipa_ctx->tx_pkt_wrapper_cache);
-fail_tx_pkt_wrapper_cache:
kmem_cache_destroy(ipa_ctx->rt_tbl_cache);
fail_rt_tbl_cache:
kmem_cache_destroy(ipa_ctx->hdr_offset_cache);
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 919a119..83c4db0 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -45,19 +45,23 @@
#define IPA_UL_DESC_FIFO_SZ 0x530
#define IPA_DL_DATA_FIFO_SZ 0x2400
#define IPA_DL_DESC_FIFO_SZ 0x8a0
+#define IPA_DL_EMB_DATA_FIFO_SZ 0x1800
+#define IPA_DL_EMB_DESC_FIFO_SZ 0x4e8
-#define IPA_SMEM_UL_DATA_FIFO_OFST 0x3dd0
-#define IPA_SMEM_UL_DESC_FIFO_OFST 0x49d0
-#define IPA_SMEM_DL_DATA_FIFO_OFST 0x4f00
-#define IPA_SMEM_DL_DESC_FIFO_OFST 0x7300
+#define IPA_SMEM_UL_DATA_FIFO_OFST 0
+#define IPA_SMEM_UL_DESC_FIFO_OFST 0xc00
+#define IPA_SMEM_DL_DATA_FIFO_OFST 0x1130
+#define IPA_SMEM_DL_DESC_FIFO_OFST 0x3530
+#define IPA_SMEM_UL_EMB_DATA_FIFO_OFST 0x3dd0
+#define IPA_SMEM_UL_EMB_DESC_FIFO_OFST 0x49d0
-#define IPA_OCIMEM_UL_DATA_FIFO_OFST 0
-#define IPA_OCIMEM_UL_DESC_FIFO_OFST (IPA_OCIMEM_UL_DATA_FIFO_OFST + \
- IPA_UL_DATA_FIFO_SZ)
-#define IPA_OCIMEM_DL_DATA_FIFO_OFST (IPA_OCIMEM_UL_DESC_FIFO_OFST + \
- IPA_UL_DESC_FIFO_SZ)
-#define IPA_OCIMEM_DL_DESC_FIFO_OFST (IPA_OCIMEM_DL_DATA_FIFO_OFST + \
- IPA_DL_DATA_FIFO_SZ)
+#define IPA_OCIMEM_DL_A2_DATA_FIFO_OFST 0
+#define IPA_OCIMEM_DL_A2_DESC_FIFO_OFST (IPA_OCIMEM_DL_A2_DATA_FIFO_OFST + \
+ IPA_DL_EMB_DATA_FIFO_SZ)
+#define IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST (IPA_OCIMEM_DL_A2_DESC_FIFO_OFST + \
+ IPA_DL_EMB_DESC_FIFO_SZ)
+#define IPA_OCIMEM_DL_IPA_DESC_FIFO_OFST (IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST + \
+ IPA_DL_EMB_DATA_FIFO_SZ)
enum ipa_pipe_type {
IPA_DL_FROM_A2,
@@ -116,7 +120,7 @@
if (dir == IPA_BRIDGE_DIR_UL)
sz = IPA_UL_DESC_FIFO_SZ;
else
- sz = IPA_DL_DESC_FIFO_SZ;
+ sz = IPA_DL_EMB_DESC_FIFO_SZ;
}
return sz;
@@ -136,7 +140,7 @@
if (dir == IPA_BRIDGE_DIR_UL)
sz = IPA_UL_DATA_FIFO_SZ;
else
- sz = IPA_DL_DATA_FIFO_SZ;
+ sz = IPA_DL_EMB_DATA_FIFO_SZ;
}
return sz;
@@ -162,6 +166,38 @@
return ep;
}
+int ipa_setup_ipa_dma_fifos(enum ipa_bridge_dir dir,
+ enum ipa_bridge_type type,
+ struct sps_mem_buffer *desc,
+ struct sps_mem_buffer *data)
+{
+ int ret;
+
+ ret = sps_setup_bam2bam_fifo(data,
+ IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST,
+ ipa_get_data_fifo_sz(dir, type), 1);
+ if (ret) {
+ IPAERR("DAFIFO setup fail %d dir %d type %d\n",
+ ret, dir, type);
+ return ret;
+ }
+
+ ret = sps_setup_bam2bam_fifo(desc,
+ IPA_OCIMEM_DL_IPA_DESC_FIFO_OFST,
+ ipa_get_desc_fifo_sz(dir, type), 1);
+ if (ret) {
+ IPAERR("DEFIFO setup fail %d dir %d type %d\n",
+ ret, dir, type);
+ return ret;
+ }
+
+ IPADBG("dir=%d type=%d Dpa=%x Dsz=%u Dva=%p dpa=%x dsz=%u dva=%p\n",
+ dir, type, data->phys_base, data->size, data->base,
+ desc->phys_base, desc->size, desc->base);
+
+ return 0;
+}
+
int ipa_setup_a2_dma_fifos(enum ipa_bridge_dir dir,
enum ipa_bridge_type type,
struct sps_mem_buffer *desc,
@@ -169,7 +205,7 @@
{
int ret;
- if (type == IPA_BRIDGE_TYPE_EMBEDDED) {
+ if (type == IPA_BRIDGE_TYPE_TETHERED) {
if (dir == IPA_BRIDGE_DIR_UL) {
desc->base = ipa_ctx->smem_pipe_mem +
IPA_SMEM_UL_DESC_FIFO_OFST;
@@ -191,26 +227,17 @@
}
} else {
if (dir == IPA_BRIDGE_DIR_UL) {
- ret = sps_setup_bam2bam_fifo(data,
- IPA_OCIMEM_UL_DATA_FIFO_OFST,
- ipa_get_data_fifo_sz(dir, type), 1);
- if (ret) {
- IPAERR("DAFIFO setup fail %d dir %d type %d\n",
- ret, dir, type);
- return ret;
- }
-
- ret = sps_setup_bam2bam_fifo(desc,
- IPA_OCIMEM_UL_DESC_FIFO_OFST,
- ipa_get_desc_fifo_sz(dir, type), 1);
- if (ret) {
- IPAERR("DEFIFO setup fail %d dir %d type %d\n",
- ret, dir, type);
- return ret;
- }
+ desc->base = ipa_ctx->smem_pipe_mem +
+ IPA_SMEM_UL_EMB_DESC_FIFO_OFST;
+ desc->phys_base = smem_virt_to_phys(desc->base);
+ desc->size = ipa_get_desc_fifo_sz(dir, type);
+ data->base = ipa_ctx->smem_pipe_mem +
+ IPA_SMEM_UL_EMB_DATA_FIFO_OFST;
+ data->phys_base = smem_virt_to_phys(data->base);
+ data->size = ipa_get_data_fifo_sz(dir, type);
} else {
ret = sps_setup_bam2bam_fifo(data,
- IPA_OCIMEM_DL_DATA_FIFO_OFST,
+ IPA_OCIMEM_DL_A2_DATA_FIFO_OFST,
ipa_get_data_fifo_sz(dir, type), 1);
if (ret) {
IPAERR("DAFIFO setup fail %d dir %d type %d\n",
@@ -219,7 +246,7 @@
}
ret = sps_setup_bam2bam_fifo(desc,
- IPA_OCIMEM_DL_DESC_FIFO_OFST,
+ IPA_OCIMEM_DL_A2_DESC_FIFO_OFST,
ipa_get_desc_fifo_sz(dir, type), 1);
if (ret) {
IPAERR("DEFIFO setup fail %d dir %d type %d\n",
@@ -289,6 +316,15 @@
ipa_in_params.desc_fifo_sz = ipa_get_desc_fifo_sz(dir, type);
ipa_in_params.data_fifo_sz = ipa_get_data_fifo_sz(dir, type);
+ if (type == IPA_BRIDGE_TYPE_EMBEDDED && dir == IPA_BRIDGE_DIR_DL) {
+ if (ipa_setup_ipa_dma_fifos(dir, type, &ipa_in_params.desc,
+ &ipa_in_params.data)) {
+ IPAERR("fail to setup IPA-DMA FIFOs dir=%d type=%d\n",
+ dir, type);
+ goto fail_get_a2_prop;
+ }
+ }
+
if (ipa_connect(&ipa_in_params, &sps_out_params, clnt_hdl)) {
IPAERR("ipa connect failed dir=%d type=%d\n", dir, type);
goto fail_get_a2_prop;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a95eafe..b0fb940 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,6 +13,9 @@
#include <linux/delay.h>
#include "ipa_i.h"
+#define IPA_A2_HOLB_TMR_EN 0x1
+#define IPA_A2_HOLB_TMR_DEFAULT_VAL 0xff
+
static void ipa_enable_data_path(u32 clnt_hdl)
{
if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
@@ -175,6 +178,31 @@
return 0;
}
+static void ipa_program_holb(struct ipa_ep_context *ep, int ipa_ep_idx)
+{
+ u32 hol_en;
+ u32 hol_tmr;
+
+ if (IPA_CLIENT_IS_PROD(ep->client))
+ return;
+
+ switch (ep->client) {
+ case IPA_CLIENT_A2_TETHERED_CONS:
+ case IPA_CLIENT_A2_EMBEDDED_CONS:
+ hol_en = IPA_A2_HOLB_TMR_EN;
+ hol_tmr = IPA_A2_HOLB_TMR_DEFAULT_VAL;
+ break;
+ default:
+ return;
+ }
+
+ IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx, hol_tmr);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx), hol_en);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx), hol_tmr);
+}
+
/**
* ipa_connect() - low-level IPA client connect
* @in: [in] input parameters from client
@@ -222,6 +250,26 @@
memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
+ if (IPA_CLIENT_IS_CONS(in->client)) {
+ ep->cmd = kzalloc(sizeof(struct ipa_ip_packet_init),
+ GFP_KERNEL);
+ if (!ep->cmd) {
+ IPAERR("failed to alloc immediate command object\n");
+ result = -ENOMEM;
+ goto fail;
+ }
+ ep->cmd->destination_pipe_index = ipa_ep_idx;
+ ep->dma_addr = dma_map_single(NULL, ep->cmd,
+ sizeof(struct ipa_ip_packet_init),
+ DMA_TO_DEVICE);
+ if (ep->dma_addr == 0 || ep->dma_addr == ~0) {
+ IPAERR("failed to DMA MAP pkt_init\n");
+ result = -ENOMEM;
+ kfree(ep->cmd);
+ goto fail;
+ }
+ }
+
ep->valid = 1;
ep->client = in->client;
ep->client_notify = in->notify;
@@ -290,21 +338,7 @@
memcpy(&sps->desc, &ep->connect.desc, sizeof(struct sps_mem_buffer));
memcpy(&sps->data, &ep->connect.data, sizeof(struct sps_mem_buffer));
- if (in->client == IPA_CLIENT_HSIC1_CONS ||
- in->client == IPA_CLIENT_HSIC2_CONS ||
- in->client == IPA_CLIENT_HSIC3_CONS ||
- in->client == IPA_CLIENT_HSIC4_CONS ||
- in->client == IPA_CLIENT_A2_TETHERED_CONS ||
- in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
- IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
- ipa_ctx->hol_timer);
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx),
- ipa_ctx->hol_en);
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx),
- ipa_ctx->hol_timer);
- }
+ ipa_program_holb(ep, ipa_ep_idx);
IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
@@ -412,6 +446,13 @@
return -EPERM;
}
+ if (IPA_CLIENT_IS_CONS(ep->client)) {
+ dma_unmap_single(NULL, ep->dma_addr,
+ sizeof(struct ipa_ip_packet_init),
+ DMA_TO_DEVICE);
+ kfree(ep->cmd);
+ }
+
ipa_enable_data_path(clnt_hdl);
memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 1b6181f..c564922 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -19,18 +19,20 @@
#define list_next_entry(pos, member) \
list_entry(pos->member.next, typeof(*pos), member)
-#define IPA_LAST_DESC_CNT 0xFFFF
#define POLLING_INACTIVITY_RX 40
-#define POLLING_MIN_SLEEP_RX 950
-#define POLLING_MAX_SLEEP_RX 1050
-#define POLLING_INACTIVITY_TX 40
-#define POLLING_MIN_SLEEP_TX 400
-#define POLLING_MAX_SLEEP_TX 500
+#define POLLING_MIN_SLEEP_RX 2350
+#define POLLING_MAX_SLEEP_RX 2450
+#define POLLING_INACTIVITY_TX 10
+#define POLLING_MIN_SLEEP_TX 100
+#define POLLING_MAX_SLEEP_TX 200
+#define RX_MAX_IND 40
static void replenish_rx_work_func(struct work_struct *work);
static struct delayed_work replenish_rx_work;
static void ipa_wq_handle_rx(struct work_struct *work);
static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
+static void ipa_wq_handle_tx(struct work_struct *work);
+static DECLARE_WORK(tx_work, ipa_wq_handle_tx);
/**
* ipa_write_done() - this function will be (eventually) called when a Tx
@@ -81,7 +83,7 @@
if (tx_pkt->callback)
tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
- kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+ kfree(tx_pkt);
}
int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
@@ -119,23 +121,13 @@
IPADBG("--curr_cnt=%d\n", sys->len);
- if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
- dma_pool_free(ipa_ctx->dma_pool,
- tx_pkt->bounce,
- tx_pkt->mem.phys_base);
- else
+ if (tx_pkt->callback) {
dma_unmap_single(NULL, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
-
- if (tx_pkt->callback)
+ tx_pkt->mem.size, DMA_TO_DEVICE);
tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+ }
- if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
- dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
- tx_pkt->mult.phys_base);
-
- kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+ kfree(tx_pkt);
cnt++;
};
@@ -154,11 +146,6 @@
goto fail;
}
- ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
- if (ret) {
- IPAERR("sps_get_config() failed %d\n", ret);
- goto fail;
- }
sys->event.options = SPS_O_EOT;
ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
if (ret) {
@@ -205,9 +192,7 @@
static void ipa_wq_handle_tx(struct work_struct *work)
{
- struct ipa_tx_pkt_wrapper *tx_pkt;
- tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
- ipa_handle_tx(tx_pkt->sys);
+ ipa_handle_tx(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT]);
}
/**
@@ -240,7 +225,7 @@
if (unlikely(!in_atomic))
mem_flag = GFP_KERNEL;
- tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
+ tx_pkt = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), mem_flag);
if (!tx_pkt) {
IPAERR("failed to alloc tx wrapper\n");
goto fail_mem_alloc;
@@ -296,14 +281,11 @@
IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
desc->opcode, desc->len, sps_flags);
IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
} else {
len = desc->len;
- INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
- if (unlikely(ipa_ctx->polling_mode))
- INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+ INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
spin_lock_irqsave(&sys->spinlock, irq_flags);
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
@@ -327,192 +309,12 @@
else
dma_unmap_single(NULL, dma_address, desc->len, DMA_TO_DEVICE);
fail_dma_map:
- kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+ kfree(tx_pkt);
fail_mem_alloc:
return -EFAULT;
}
/**
- * ipa_send() - Send multiple descriptors in one HW transaction
- * @sys: system pipe context
- * @num_desc: number of packets
- * @desc: packets to send (may be immediate command or data)
- * @in_atomic: whether caller is in atomic context
- *
- * This function is used for system-to-bam connection.
- * - SPS driver expect struct sps_transfer which will contain all the data
- * for a transaction
- * - The sps_transfer struct will be pointing to bounce buffers for
- * its DMA command (immediate command and data)
- * - ipa_tx_pkt_wrapper will be used for each ipa
- * descriptor (allocated from wrappers cache)
- * - The wrapper struct will be configured for each ipa-desc payload and will
- * contain information which will be later used by the user callbacks
- * - each transfer will be made by calling to sps_transfer()
- * - Each packet (command or data) that will be sent will also be saved in
- * ipa_sys_context for later check that all data was sent
- *
- * Return codes: 0: success, -EFAULT: failure
- */
-int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
- bool in_atomic)
-{
- struct ipa_tx_pkt_wrapper *tx_pkt;
- struct ipa_tx_pkt_wrapper *next_pkt;
- struct sps_transfer transfer = { 0 };
- struct sps_iovec *iovec;
- unsigned long irq_flags;
- dma_addr_t dma_addr;
- int i = 0;
- int j;
- int result;
- int fail_dma_wrap = 0;
- uint size = num_desc * sizeof(struct sps_iovec);
- u32 mem_flag = GFP_ATOMIC;
-
- if (unlikely(!in_atomic))
- mem_flag = GFP_KERNEL;
-
- transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr);
- transfer.iovec_phys = dma_addr;
- transfer.iovec_count = num_desc;
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- if (!transfer.iovec) {
- IPAERR("fail to alloc DMA mem for sps xfr buff\n");
- goto failure_coherent;
- }
-
- for (i = 0; i < num_desc; i++) {
- fail_dma_wrap = 0;
- tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
- mem_flag);
- if (!tx_pkt) {
- IPAERR("failed to alloc tx wrapper\n");
- goto failure;
- }
- /*
- * first desc of set is "special" as it holds the count and
- * other info
- */
- if (i == 0) {
- transfer.user = tx_pkt;
- tx_pkt->mult.phys_base = dma_addr;
- tx_pkt->mult.base = transfer.iovec;
- tx_pkt->mult.size = size;
- tx_pkt->cnt = num_desc;
- INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
- }
-
- iovec = &transfer.iovec[i];
- iovec->flags = 0;
-
- INIT_LIST_HEAD(&tx_pkt->link);
- tx_pkt->type = desc[i].type;
-
- tx_pkt->mem.base = desc[i].pyld;
- tx_pkt->mem.size = desc[i].len;
-
- if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
- WARN_ON(tx_pkt->mem.size > 512);
-
- /*
- * Due to a HW limitation, we need to make sure that the
- * packet does not cross a 1KB boundary
- */
- tx_pkt->bounce =
- dma_pool_alloc(ipa_ctx->dma_pool,
- mem_flag,
- &tx_pkt->mem.phys_base);
- if (!tx_pkt->bounce) {
- tx_pkt->mem.phys_base = 0;
- } else {
- WARN_ON(!ipa_straddle_boundary(
- (u32)tx_pkt->mem.phys_base,
- (u32)tx_pkt->mem.phys_base +
- tx_pkt->mem.size - 1, 1024));
- memcpy(tx_pkt->bounce, tx_pkt->mem.base,
- tx_pkt->mem.size);
- }
- } else {
- tx_pkt->mem.phys_base =
- dma_map_single(NULL, tx_pkt->mem.base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
- }
- if (!tx_pkt->mem.phys_base) {
- IPAERR("failed to alloc tx wrapper\n");
- fail_dma_wrap = 1;
- goto failure;
- }
-
- tx_pkt->sys = sys;
- tx_pkt->callback = desc[i].callback;
- tx_pkt->user1 = desc[i].user1;
- tx_pkt->user2 = desc[i].user2;
-
- /*
- * Point the iovec to the bounce buffer and
- * add this packet to system pipe context.
- */
- iovec->addr = tx_pkt->mem.phys_base;
- list_add_tail(&tx_pkt->link, &sys->head_desc_list);
-
- /*
- * Special treatment for immediate commands, where the structure
- * of the descriptor is different
- */
- if (desc[i].type == IPA_IMM_CMD_DESC) {
- iovec->size = desc[i].opcode;
- iovec->flags |= SPS_IOVEC_FLAG_IMME;
- } else {
- iovec->size = desc[i].len;
- }
-
- if (i == (num_desc - 1)) {
- iovec->flags |= SPS_IOVEC_FLAG_EOT;
- /* "mark" the last desc */
- tx_pkt->cnt = IPA_LAST_DESC_CNT;
- }
- }
-
- result = sps_transfer(sys->ep->ep_hdl, &transfer);
- if (result) {
- IPAERR("sps_transfer failed rc=%d\n", result);
- goto failure;
- }
-
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- return 0;
-
-failure:
- tx_pkt = transfer.user;
- for (j = 0; j < i; j++) {
- next_pkt = list_next_entry(tx_pkt, link);
- list_del(&tx_pkt->link);
- if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
- dma_pool_free(ipa_ctx->dma_pool,
- tx_pkt->bounce,
- tx_pkt->mem.phys_base);
- else
- dma_unmap_single(NULL, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
- kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
- tx_pkt = next_pkt;
- }
- if (i < num_desc)
- /* last desc failed */
- if (fail_dma_wrap)
- kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
- if (transfer.iovec_phys)
- dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
- transfer.iovec_phys);
-failure_coherent:
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- return -EFAULT;
-}
-
-/**
* ipa_sps_irq_cmd_ack - callback function which will be called by SPS driver after an
* immediate command is complete.
* @user1: pointer to the descriptor of the transfer
@@ -543,7 +345,6 @@
*/
int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
{
- struct ipa_desc *desc;
int result = 0;
ipa_inc_client_enable_clks();
@@ -563,22 +364,10 @@
}
wait_for_completion(&descr->xfer_done);
} else {
- desc = &descr[num_desc - 1];
- init_completion(&desc->xfer_done);
-
- if (desc->callback || desc->user1)
- WARN_ON(1);
-
- desc->callback = ipa_sps_irq_cmd_ack;
- desc->user1 = desc;
- if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
- descr, false)) {
- IPAERR("fail to send multiple immediate command set\n");
+ IPAERR("unsupported chaining multiple IC\n");
result = -EFAULT;
goto bail;
}
- wait_for_completion(&desc->xfer_done);
- }
IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
bail:
@@ -597,21 +386,13 @@
static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
{
struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
- struct ipa_tx_pkt_wrapper *tx_pkt;
int ret;
IPADBG("event %d notified\n", notify->event_id);
switch (notify->event_id) {
case SPS_EVENT_EOT:
- tx_pkt = notify->data.transfer.user;
if (!atomic_read(&sys->curr_polling_state)) {
- ret = sps_get_config(sys->ep->ep_hdl,
- &sys->ep->connect);
- if (ret) {
- IPAERR("sps_get_config() failed %d\n", ret);
- break;
- }
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(sys->ep->ep_hdl,
@@ -621,7 +402,7 @@
break;
}
atomic_set(&sys->curr_polling_state, 1);
- queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+ queue_work(ipa_ctx->tx_wq, &tx_work);
}
break;
default:
@@ -654,6 +435,47 @@
}
}
+static void ipa_handle_tag_rsp(struct ipa_a5_mux_hdr *mux_hdr)
+{
+ struct completion *compl;
+ struct ipa_tree_node *node;
+
+ /* retrieve the compl object from tag value */
+ mux_hdr++;
+ compl = (struct completion *) ntohl(*((u32 *)mux_hdr));
+ IPADBG("%x %x %p\n", *(u32 *)mux_hdr, *((u32 *)mux_hdr + 1), compl);
+
+ mutex_lock(&ipa_ctx->lock);
+ node = ipa_search(&ipa_ctx->tag_tree, (u32)compl);
+ if (node) {
+ complete_all(compl);
+ rb_erase(&node->node, &ipa_ctx->tag_tree);
+ kmem_cache_free(ipa_ctx->tree_node_cache, node);
+ } else {
+ WARN_ON(1);
+ }
+ mutex_unlock(&ipa_ctx->lock);
+}
+
+static void ipa_dejitter(bool limit)
+{
+ struct sk_buff *skb;
+ int len = skb_queue_len(&ipa_ctx->rx_list);
+ int i;
+ void *cookie;
+ ipa_notify_cb cb;
+
+ if (limit && len >= RX_MAX_IND)
+ len = RX_MAX_IND;
+
+ for (i = len; i > 0; i--) {
+ skb = __skb_dequeue(&ipa_ctx->rx_list);
+ cb = (ipa_notify_cb)*(u32 *)&(skb->cb[0]);
+ cookie = (void *)*(u32 *)&(skb->cb[4]);
+ cb(cookie, IPA_RECEIVE, (unsigned long)skb);
+ }
+}
+
/**
* ipa_handle_rx_core() - The core functionality of packet reception. This
* function is read from multiple code paths.
@@ -675,13 +497,9 @@
struct ipa_rx_pkt_wrapper *rx_pkt;
struct sk_buff *rx_skb;
struct sps_iovec iov;
- unsigned int pull_len;
- unsigned int padding;
int ret;
struct ipa_ep_context *ep;
int cnt = 0;
- struct completion *compl;
- struct ipa_tree_node *node;
unsigned int src_pipe;
while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
@@ -721,7 +539,7 @@
rx_skb->tail = rx_skb->data + rx_pkt->len;
rx_skb->len = rx_pkt->len;
rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
- kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
+ kfree(rx_pkt);
mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
@@ -736,29 +554,9 @@
IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
- if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
- if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
- /* retrieve the compl object from tag value */
- mux_hdr++;
- compl = (struct completion *)
- ntohl(*((u32 *)mux_hdr));
- IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
- *((u32 *)mux_hdr + 1), compl);
-
- mutex_lock(&ipa_ctx->lock);
- node = ipa_search(&ipa_ctx->tag_tree,
- (u32)compl);
- if (node) {
- complete_all(compl);
- rb_erase(&node->node,
- &ipa_ctx->tag_tree);
- kmem_cache_free(
- ipa_ctx->tree_node_cache, node);
- } else {
- WARN_ON(1);
- }
- mutex_unlock(&ipa_ctx->lock);
- }
+ if (mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG) {
+ if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL)
+ ipa_handle_tag_rsp(mux_hdr);
dev_kfree_skb(rx_skb);
ipa_replenish_rx_cache();
++cnt;
@@ -769,38 +567,22 @@
* Any packets arriving over AMPDU_TX should be dispatched
* to the regular WLAN RX data-path.
*/
- if (unlikely(src_pipe == WLAN_AMPDU_TX_EP))
+ if (src_pipe == WLAN_AMPDU_TX_EP)
src_pipe = WLAN_PROD_TX_EP;
- if (unlikely(src_pipe >= IPA_NUM_PIPES ||
- !ipa_ctx->ep[src_pipe].valid ||
- !ipa_ctx->ep[src_pipe].client_notify)) {
- IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
- src_pipe, ipa_ctx->ep[src_pipe].valid,
- ipa_ctx->ep[src_pipe].client_notify);
- dev_kfree_skb(rx_skb);
- ipa_replenish_rx_cache();
- ++cnt;
- continue;
- }
+ WARN_ON(src_pipe >= IPA_NUM_PIPES);
ep = &ipa_ctx->ep[src_pipe];
- pull_len = sizeof(struct ipa_a5_mux_hdr);
-
- /*
- * IP packet starts on word boundary
- * remove the MUX header and any padding and pass the frame to
- * the client which registered a rx callback on the "src pipe"
- */
- padding = ep->cfg.hdr.hdr_len & 0x3;
- if (padding)
- pull_len += 4 - padding;
-
- IPADBG("pulling %d bytes from skb\n", pull_len);
- skb_pull(rx_skb, pull_len);
+ IPADBG("pulling %d bytes from skb\n", ep->pull_len);
+ skb_pull(rx_skb, ep->pull_len);
ipa_replenish_rx_cache();
- ep->client_notify(ep->priv, IPA_RECEIVE,
- (unsigned long)(rx_skb));
+ if (ep->client_notify) {
+ __skb_queue_tail(&ipa_ctx->rx_list, rx_skb);
+ *(u32 *)&(rx_skb->cb[0]) = (u32)ep->client_notify;
+ *(u32 *)&(rx_skb->cb[4]) = (u32)ep->priv;
+ } else {
+ dev_kfree_skb(rx_skb);
+ }
cnt++;
};
@@ -819,11 +601,6 @@
goto fail;
}
- ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
- if (ret) {
- IPAERR("sps_get_config() failed %d\n", ret);
- goto fail;
- }
sys->event.options = SPS_O_EOT;
ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
if (ret) {
@@ -870,12 +647,6 @@
switch (notify->event_id) {
case SPS_EVENT_EOT:
if (!atomic_read(&sys->curr_polling_state)) {
- ret = sps_get_config(sys->ep->ep_hdl,
- &sys->ep->connect);
- if (ret) {
- IPAERR("sps_get_config() failed %d\n", ret);
- break;
- }
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(sys->ep->ep_hdl,
@@ -925,8 +696,10 @@
} else {
inactive_cycles = 0;
}
+ ipa_dejitter(true);
} while (inactive_cycles <= POLLING_INACTIVITY_RX);
+ ipa_dejitter(false);
ipa_rx_switch_to_intr_mode(sys);
ipa_dec_client_disable_clks();
}
@@ -1062,6 +835,7 @@
break;
case 2:
sys_idx = ipa_ep_idx;
+ ipa_ctx->sys[sys_idx].max_len = sys_in->desc_fifo_sz / 8 - 2;
INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
switch_to_intr_tx_work_func);
break;
@@ -1176,9 +950,87 @@
dev_kfree_skb(skb);
}
-static void ipa_tx_cmd_comp(void *user1, void *user2)
+static int ipa_send_two(struct sk_buff *skb, struct ipa_sys_context *sys,
+ int dst_ep_idx)
{
- kfree(user1);
+ struct ipa_tx_pkt_wrapper *tx_pktc;
+ struct ipa_tx_pkt_wrapper *tx_pktd;
+ struct ipa_ep_context *ep = &ipa_ctx->ep[dst_ep_idx];
+ unsigned long irq_flags;
+ dma_addr_t dma_addrd;
+ int rc = -ENOMEM;
+
+ tx_pktc = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
+ if (!tx_pktc) {
+ IPAERR("failed to alloc tx wrapper C\n");
+ goto fail_mem_alloc_c;
+ }
+
+ tx_pktd = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
+ if (!tx_pktd) {
+ IPAERR("failed to alloc tx wrapper D\n");
+ goto fail_mem_alloc_d;
+ }
+
+ dma_addrd = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
+ if (!dma_addrd) {
+ IPAERR("failed to DMA wrap\n");
+ goto fail_dma_map_d;
+ }
+
+ INIT_LIST_HEAD(&tx_pktc->link);
+ tx_pktc->callback = NULL;
+
+ INIT_LIST_HEAD(&tx_pktd->link);
+ tx_pktd->mem.phys_base = dma_addrd;
+ tx_pktd->mem.base = skb->data;
+ tx_pktd->mem.size = skb->len;
+ tx_pktd->callback = ipa_tx_comp_usr_notify_release;
+ tx_pktd->user1 = skb;
+ tx_pktd->user2 = (void *)dst_ep_idx;
+
+ spin_lock_irqsave(&sys->spinlock, irq_flags);
+ if (sys->len >= sys->max_len)
+ goto fail_oom;
+ list_add_tail(&tx_pktc->link, &sys->head_desc_list);
+ if (sps_transfer_one(sys->ep->ep_hdl, ep->dma_addr, IPA_IP_PACKET_INIT,
+ tx_pktc, SPS_IOVEC_FLAG_IMME |
+ SPS_IOVEC_FLAG_NO_SUBMIT))
+ IPAERR("sps_transfer_one 0 failed\n");
+ list_add_tail(&tx_pktd->link, &sys->head_desc_list);
+ if (sps_transfer_one(sys->ep->ep_hdl, dma_addrd, skb->len, tx_pktd,
+ SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT))
+ IPAERR("sps_transfer_one 1 failed\n");
+ sys->len += 2;
+ spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+ return 0;
+
+fail_oom:
+ dma_unmap_single(NULL, dma_addrd, skb->len, DMA_TO_DEVICE);
+fail_dma_map_d:
+ kfree(tx_pktd);
+fail_mem_alloc_d:
+ kfree(tx_pktc);
+fail_mem_alloc_c:
+ return rc;
+}
+
+static int ipa_send_data_hw_path(struct sk_buff *skb,
+ struct ipa_sys_context *sys, int dst_ep_idx)
+{
+ struct ipa_desc desc;
+
+ desc.pyld = skb->data;
+ desc.len = skb->len;
+ desc.type = IPA_DATA_DESC_SKB;
+ desc.callback = ipa_tx_comp_usr_notify_release;
+ desc.user1 = skb;
+ desc.user2 = (void *)dst_ep_idx;
+
+ if (ipa_send_one(sys, &desc, true))
+ return -EFAULT;
+
+ return 0;
}
/**
@@ -1211,76 +1063,42 @@
int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
struct ipa_tx_meta *meta)
{
- struct ipa_desc desc[2];
int ipa_ep_idx;
- struct ipa_ip_packet_init *cmd;
-
- memset(&desc, 0, 2 * sizeof(struct ipa_desc));
ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
if (unlikely(ipa_ep_idx == -1)) {
IPAERR("dest EP does not exist.\n");
- goto fail_gen;
+ goto fail;
}
if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
IPAERR("dest EP not valid.\n");
- goto fail_gen;
+ goto fail;
}
if (IPA_CLIENT_IS_CONS(dst)) {
- cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
- if (!cmd) {
- IPAERR("failed to alloc immediate command object\n");
- goto fail_mem_alloc;
- }
-
- cmd->destination_pipe_index = ipa_ep_idx;
- if (meta && meta->mbim_stream_id_valid)
- cmd->metadata = meta->mbim_stream_id;
- desc[0].opcode = IPA_IP_PACKET_INIT;
- desc[0].pyld = cmd;
- desc[0].len = sizeof(struct ipa_ip_packet_init);
- desc[0].type = IPA_IMM_CMD_DESC;
- desc[0].callback = ipa_tx_cmd_comp;
- desc[0].user1 = cmd;
- desc[1].pyld = skb->data;
- desc[1].len = skb->len;
- desc[1].type = IPA_DATA_DESC_SKB;
- desc[1].callback = ipa_tx_comp_usr_notify_release;
- desc[1].user1 = skb;
- desc[1].user2 = (void *)ipa_ep_idx;
-
- if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
- true)) {
- IPAERR("fail to send immediate command\n");
- goto fail_send;
+ if (ipa_send_two(skb, &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT],
+ ipa_ep_idx)) {
+ IPAERR("fail to send pkt_init+skb dst=%d skb=%p\n",
+ dst, skb);
+ goto fail;
}
IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
} else if (dst == IPA_CLIENT_A5_WLAN_AMPDU_PROD) {
- desc[0].pyld = skb->data;
- desc[0].len = skb->len;
- desc[0].type = IPA_DATA_DESC_SKB;
- desc[0].callback = ipa_tx_comp_usr_notify_release;
- desc[0].user1 = skb;
- desc[0].user2 = (void *)ipa_ep_idx;
-
- if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
- &desc[0], true)) {
- IPAERR("fail to send skb\n");
- goto fail_gen;
+ if (ipa_send_data_hw_path(skb,
+ &ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
+ ipa_ep_idx)) {
+ IPAERR("fail to send skb dst=%d skb=%p\n", dst, skb);
+ goto fail;
}
} else {
IPAERR("%d PROD is not supported.\n", dst);
- goto fail_gen;
+ goto fail;
}
return 0;
-fail_send:
- kfree(cmd);
-fail_mem_alloc:
-fail_gen:
+fail:
return -EFAULT;
}
EXPORT_SYMBOL(ipa_tx_dp);
@@ -1316,8 +1134,7 @@
rx_len_cached = sys->len;
while (rx_len_cached < IPA_RX_POOL_CEIL) {
- rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
- flag);
+ rx_pkt = kmalloc(sizeof(struct ipa_rx_pkt_wrapper), flag);
if (!rx_pkt) {
IPAERR("failed to alloc rx wrapper\n");
goto fail_kmem_cache_alloc;
@@ -1365,7 +1182,7 @@
fail_dma_mapping:
dev_kfree_skb(rx_pkt->skb);
fail_skb_alloc:
- kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
+ kfree(rx_pkt);
fail_kmem_cache_alloc:
if (rx_len_cached == 0) {
IPA_STATS_INC_CNT(ipa_ctx->stats.rx_repl_repost);
@@ -1397,7 +1214,7 @@
dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
DMA_FROM_DEVICE);
dev_kfree_skb(rx_pkt->skb);
- kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
+ kfree(rx_pkt);
}
}
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index b57194e..a818931 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -363,6 +363,9 @@
bool desc_fifo_client_allocated;
bool data_fifo_client_allocated;
bool suspended;
+ unsigned int pull_len;
+ struct ipa_ip_packet_init *cmd;
+ dma_addr_t dma_addr;
};
/**
@@ -378,6 +381,7 @@
struct ipa_sys_context {
struct list_head head_desc_list;
u32 len;
+ u32 max_len;
spinlock_t spinlock;
struct sps_register_event event;
struct ipa_ep_context *ep;
@@ -636,8 +640,6 @@
struct kmem_cache *hdr_cache;
struct kmem_cache *hdr_offset_cache;
struct kmem_cache *rt_tbl_cache;
- struct kmem_cache *tx_pkt_wrapper_cache;
- struct kmem_cache *rx_pkt_wrapper_cache;
struct kmem_cache *tree_node_cache;
unsigned long rt_idx_bitmap[IPA_IP_MAX];
struct mutex lock;
@@ -687,6 +689,7 @@
/* store HOLB configuration for WLAN TX pipes */
u32 hol_en;
u32 hol_timer;
+ struct sk_buff_head rx_list;
};
/**
@@ -775,8 +778,6 @@
u32 *consumer_handle);
int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
bool in_atomic);
-int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
- bool in_atomic);
int ipa_get_ep_mapping(enum ipa_operating_mode mode,
enum ipa_client_type client);
int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 264de0d..046c4d4 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -32,6 +32,24 @@
{ 19, -1, -1, -1, -1, 11, 15, 8, 6, 2, 1, 5, 14, 16, 17, 18, -1, 10, 9, 7, 3, 4 },
};
+static unsigned int ipa_calc_pull_len(u32 hdr_len)
+{
+ unsigned int pull_len, padding;
+
+ pull_len = sizeof(struct ipa_a5_mux_hdr);
+
+ /*
+ * IP packet starts on word boundary
+ * remove the MUX header and any padding and pass the frame to
+ * the client which registered a rx callback on the "src pipe"
+ */
+ padding = hdr_len & 0x3;
+ if (padding)
+ pull_len += 4 - padding;
+
+ return pull_len;
+}
+
/**
* ipa_cfg_route() - configure IPA route
* @route: IPA route
@@ -751,6 +769,9 @@
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_HDR_n_OFST_v2(clnt_hdl), val);
+ if (IPA_CLIENT_IS_PROD(ep->client))
+ ep->pull_len = ipa_calc_pull_len(ipa_ep_cfg->hdr_len);
+
return 0;
}
EXPORT_SYMBOL(ipa_cfg_ep_hdr);
@@ -1263,4 +1284,3 @@
else
return 0;
}
-
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index add9522..93f2366 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -1683,6 +1683,12 @@
return -EINVAL;
}
+ res = teth_request_resource();
+ if (res) {
+ TETH_ERR("request_resource() failed.\n");
+ return res;
+ }
+
memcpy(&teth_ctx->aggr_params,
aggr_params,
sizeof(struct teth_aggr_params));
@@ -1693,6 +1699,8 @@
res = teth_set_aggregation();
if (res)
TETH_ERR("Failed setting aggregation params\n");
+
+ ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
TETH_DBG_FUNC_EXIT();
return res;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index a85e31c..ac0b1d9 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -22,6 +22,10 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/log2.h>
+#include <linux/qpnp/power-on.h>
+
+/* Common PNP defines */
+#define QPNP_PON_REVISION2(base) (base + 0x01)
/* PON common register addresses */
#define QPNP_PON_RT_STS(base) (base + 0x10)
@@ -38,6 +42,8 @@
#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
#define QPNP_PON_PS_HOLD_RST_CTL(base) (base + 0x5A)
+#define QPNP_PON_PS_HOLD_RST_CTL2(base) (base + 0x5B)
+#define QPNP_PON_TRIGGER_EN(base) (base + 0x80)
#define QPNP_PON_WARM_RESET_TFT BIT(4)
@@ -140,17 +146,31 @@
int qpnp_pon_system_pwr_off(bool reset)
{
int rc;
+ u8 reg;
+ u16 rst_en_reg;
struct qpnp_pon *pon = sys_reset_dev;
if (!pon)
return -ENODEV;
- rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
- QPNP_PON_RESET_EN, 0);
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_REVISION2(pon->base), ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read addr=%x, rc(%d)\n",
+ QPNP_PON_REVISION2(pon->base), rc);
+ return rc;
+ }
+
+ if (reg == 0x00)
+ rst_en_reg = QPNP_PON_PS_HOLD_RST_CTL(pon->base);
+ else
+ rst_en_reg = QPNP_PON_PS_HOLD_RST_CTL2(pon->base);
+
+ rc = qpnp_pon_masked_write(pon, rst_en_reg, QPNP_PON_RESET_EN, 0);
if (rc)
dev_err(&pon->spmi->dev,
- "Unable to write to addr=%x, rc(%d)\n",
- QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+ "Unable to write to addr=%x, rc(%d)\n", rst_en_reg, rc);
/*
* We need 10 sleep clock cycles here. But since the clock is
@@ -167,13 +187,11 @@
"Unable to write to addr=%x, rc(%d)\n",
QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
- rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
- QPNP_PON_RESET_EN,
- QPNP_PON_RESET_EN);
+ rc = qpnp_pon_masked_write(pon, rst_en_reg, QPNP_PON_RESET_EN,
+ QPNP_PON_RESET_EN);
if (rc)
dev_err(&pon->spmi->dev,
- "Unable to write to addr=%x, rc(%d)\n",
- QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+ "Unable to write to addr=%x, rc(%d)\n", rst_en_reg, rc);
return rc;
}
@@ -223,6 +241,39 @@
}
EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
+/**
+ * qpnp_pon_trigger_config - Configures (enable/disable) the PON trigger source
+ * @pon_src: PON source to be configured
+ * @enable: to enable or disable the PON trigger
+ *
+ * This function configures the power-on trigger capability of a
+ * PON source. If a specific PON trigger is disabled it cannot act
+ * as a power-on source to the PMIC.
+ */
+
+int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable)
+{
+ struct qpnp_pon *pon = sys_reset_dev;
+ int rc;
+
+ if (!pon)
+ return -EPROBE_DEFER;
+
+ if (pon_src < PON_SMPL || pon_src > PON_KPDPWR_N) {
+ dev_err(&pon->spmi->dev, "Invalid PON source\n");
+ return -EINVAL;
+ }
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_TRIGGER_EN(pon->base),
+ BIT(pon_src), enable ? BIT(pon_src) : 0);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to write to addr=%x, rc(%d)\n",
+ QPNP_PON_TRIGGER_EN(pon->base), rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_pon_trigger_config);
+
static struct qpnp_pon_config *
qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
{
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 442d18f..be62408 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -914,7 +914,7 @@
static inline int qpnp_enable_pwm_mode(struct qpnp_pwm_config *pwm_conf)
{
- if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START ||
+ if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START &&
pwm_conf->channel_id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
return QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL;
return QPNP_ENABLE_PWM_MODE;
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 23c346a..2e77114 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1583,10 +1583,7 @@
for (i = 0; i < transfer->iovec_count; i++) {
u32 flags = iovec->flags;
- if (iovec->addr == 0) {
- SPS_ERR("sps:%s:iovec address is invalid.\n", __func__);
- return SPS_ERROR;
- } else if (iovec->size > SPS_IOVEC_MAX_SIZE) {
+ if (iovec->size > SPS_IOVEC_MAX_SIZE) {
SPS_ERR("sps:%s:iovec size is invalid.\n", __func__);
return SPS_ERROR;
}
@@ -1988,6 +1985,35 @@
EXPORT_SYMBOL(sps_get_unused_desc_num);
/**
+ * Vote for or relinquish BAM DMA clock
+ *
+ */
+int sps_ctrl_bam_dma_clk(bool clk_on)
+{
+ int ret;
+
+ SPS_DBG("sps:%s.", __func__);
+
+ if (!sps->is_ready)
+ return -EPROBE_DEFER;
+
+ if (clk_on == true) {
+ SPS_DBG("sps:vote for bam dma clk.\n");
+ ret = clk_prepare_enable(sps->bamdma_clk);
+ if (ret) {
+ SPS_ERR("sps:fail to enable bamdma_clk:ret=%d\n", ret);
+ return ret;
+ }
+ } else {
+ SPS_DBG("sps:relinquish bam dma clk.\n");
+ clk_disable_unprepare(sps->bamdma_clk);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sps_ctrl_bam_dma_clk);
+
+/**
* Register a BAM device
*
*/
@@ -2528,11 +2554,13 @@
SPS_ERR("sps:sps_device_init err.");
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
clk_disable_unprepare(sps->dfab_clk);
+ clk_disable_unprepare(sps->bamdma_clk);
#endif
goto sps_device_init_err;
}
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
clk_disable_unprepare(sps->dfab_clk);
+ clk_disable_unprepare(sps->bamdma_clk);
#endif
sps->is_ready = true;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 64e8d7a..55cbfe9 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -129,23 +129,73 @@
[HSIC_BAM] = hsic_cons_release_resource,
};
-static enum ipa_rm_event cur_prod_state[MAX_BAMS];
-static enum ipa_rm_event cur_cons_state[MAX_BAMS];
-static int sched_lpm;
-static int lpm_wait_handshake;
-static struct completion prod_avail[MAX_BAMS];
-static struct completion cons_avail[MAX_BAMS];
-static struct completion cons_released[MAX_BAMS];
-static struct completion prod_released[MAX_BAMS];
+struct usb_bam_ipa_handshake_info {
+ enum ipa_rm_event cur_prod_state[MAX_BAMS];
+ enum ipa_rm_event cur_cons_state[MAX_BAMS];
+ bool lpm_wait_handshake[MAX_BAMS];
+ int connect_complete;
+ bool lpm_wait_pipes;
+ int bus_suspend;
+ bool disconnected;
+ bool in_lpm[MAX_BAMS];
+
+ int (*wake_cb)(void *);
+ void *wake_param;
+ void (*start)(void *, enum usb_bam_pipe_dir);
+ void (*stop)(void *, enum usb_bam_pipe_dir);
+ void *start_stop_param;
+
+ u32 src_idx;
+ u32 dst_idx;
+ bool cons_stopped;
+ bool prod_stopped;
+
+ struct completion prod_avail[MAX_BAMS];
+ struct completion cons_avail[MAX_BAMS];
+ struct completion cons_released[MAX_BAMS];
+ struct completion prod_released[MAX_BAMS];
+
+ struct mutex suspend_resume_mutex;
+ struct work_struct resume_work;
+ struct work_struct suspend_work;
+ struct work_struct finish_suspend_work;
+};
+
+static spinlock_t usb_bam_ipa_handshake_info_lock;
+static struct usb_bam_ipa_handshake_info info;
static spinlock_t usb_bam_peer_handshake_info_lock;
static struct usb_bam_peer_handshake_info peer_handshake_info;
static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
static struct usb_bam_pipe_connect *usb_bam_connections;
static struct usb_bam_ctx_type ctx;
+static struct device *hsic_host_dev;
+static bool hsic_host_dev_resumed_from_cons_request;
+
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
+static void wait_for_prod_release(enum usb_bam cur_bam);
+static void wait_for_cons_release(enum usb_bam cur_bam);
+
+void msm_bam_set_hsic_host_dev(struct device *dev)
+{
+ if (dev) {
+ /* Hold the device until allowing lpm */
+ info.in_lpm[HSIC_BAM] = false;
+ pr_debug("%s: Getting hsic device %x\n", __func__,
+ (int)dev);
+ pm_runtime_get(dev);
+ } else if (hsic_host_dev) {
+ pr_debug("%s: Putting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ /* Just free previous device*/
+ info.in_lpm[HSIC_BAM] = true;
+ pm_runtime_put(hsic_host_dev);
+ }
+
+ hsic_host_dev = dev;
+}
static int get_bam_type_from_core_name(const char *name)
{
@@ -184,6 +234,8 @@
struct sps_pipe *pipe = NULL;
int i;
+ pr_debug("%s: enter\n", __func__);
+
/*
* Since we configure global incativity timer for all pipes
* and not per each pipe, it is enough to use some pipe
@@ -192,14 +244,15 @@
*/
for (i = 0; i < ctx.max_connections; i++) {
pipe_connect = &usb_bam_connections[i];
- if (pipe_connect->bam_type == bam) {
+ if (pipe_connect->bam_type == bam &&
+ pipe_connect->enabled) {
pipe = ctx.usb_bam_sps.sps_pipes[i];
break;
}
}
if (!pipe) {
- pr_err("%s: Bam %s has no pipes\n", __func__,
+ pr_warning("%s: Bam %s has no connected pipes\n", __func__,
bam_enable_strings[bam]);
return;
}
@@ -457,6 +510,7 @@
pr_err("%s: ipa_connect failed\n", __func__);
return ret;
}
+ pipe_connect->ipa_clnt_hdl = clnt_hdl;
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -514,16 +568,6 @@
goto error;
}
- spin_lock(&usb_bam_lock);
-
- /* Set global inactivity timer upon first pipe connection */
- if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
- ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
- pipe_connect->inactivity_notify)
- usb_bam_set_inactivity_timer(pipe_connect->bam_type);
-
- spin_unlock(&usb_bam_lock);
-
return 0;
error:
@@ -579,6 +623,31 @@
return 0;
}
+static void usb_bam_resume_core(enum usb_bam cur_bam)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+
+ if (cur_bam != HSUSB_BAM)
+ return;
+ BUG_ON(trans == NULL);
+ pr_debug("%s: resume core", __func__);
+ pm_runtime_resume(trans->dev);
+}
+
+static void usb_bam_start_lpm(bool disconnect)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+ BUG_ON(trans == NULL);
+ pr_debug("%s: Going to LPM\n", __func__);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake[HSUSB_BAM] = false;
+ info.lpm_wait_pipes = 0;
+ if (disconnect)
+ pm_runtime_put_noidle(trans->dev);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pm_runtime_suspend(trans->dev);
+}
+
int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
int ret;
@@ -608,26 +677,144 @@
}
spin_lock(&usb_bam_lock);
-
/* Check if BAM requires RESET before connect and reset of first pipe */
if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
(ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+ spin_unlock(&usb_bam_lock);
ret = connect_pipe(idx, bam_pipe_idx);
if (ret) {
pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
- spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 1;
+ spin_lock(&usb_bam_lock);
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
-
spin_unlock(&usb_bam_lock);
+
return 0;
}
+static int ipa_suspend_pipes(void)
+{
+ struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+ int ret1, ret2;
+
+ dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+ src_pipe_connect = &usb_bam_connections[info.src_idx];
+
+ if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+ src_pipe_connect->ipa_clnt_hdl == -1) {
+ pr_err("%s: One of handles is -1, not connected?", __func__);
+ }
+
+ ret1 = ipa_suspend(dst_pipe_connect->ipa_clnt_hdl);
+ if (ret1)
+ pr_err("%s: ipa_suspend on dst failed with %d", __func__, ret1);
+ ret2 = ipa_suspend(src_pipe_connect->ipa_clnt_hdl);
+ if (ret2)
+ pr_err("%s: ipa_suspend on src failed with %d", __func__, ret2);
+
+ return ret1 | ret2;
+}
+
+static int ipa_resume_pipes(void)
+{
+ struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+ int ret1, ret2;
+
+ src_pipe_connect = &usb_bam_connections[info.src_idx];
+ dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+
+ if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+ src_pipe_connect->ipa_clnt_hdl == -1) {
+ pr_err("%s: One of handles is -1, not connected?", __func__);
+ }
+
+ ret1 = ipa_resume(dst_pipe_connect->ipa_clnt_hdl);
+ if (ret1)
+ pr_err("%s: ipa_resume on dst failed with %d", __func__, ret1);
+ ret2 = ipa_resume(src_pipe_connect->ipa_clnt_hdl);
+ if (ret2)
+ pr_err("%s: ipa_resume on src failed with %d", __func__, ret2);
+
+ return ret1 | ret2;
+}
+
+static void usb_bam_finish_suspend(void)
+{
+ int ret;
+ u32 cons_empty;
+ struct sps_pipe *cons_pipe = ctx.usb_bam_sps.sps_pipes[info.dst_idx];
+ struct usb_bam_pipe_connect *pipe_connect = &
+ usb_bam_connections[info.dst_idx];
+ enum usb_bam cur_bam = pipe_connect->bam_type;
+
+ if (cur_bam != HSUSB_BAM) {
+ pr_err("%s: Wrong type of BAM=%s\n", __func__,
+ bam_enable_strings[cur_bam]);
+ return;
+ }
+
+ mutex_lock(&info.suspend_resume_mutex);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ /* If cable was disconnected, let disconnection seq do everything */
+ if (info.disconnected || info.cons_stopped) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: Cable disconnected\n", __func__);
+ return;
+ }
+
+ /* If resume was called don't finish this work */
+ if (!info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Bus resume in progress\n", __func__);
+ goto no_lpm;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ ret = sps_is_pipe_empty(cons_pipe, &cons_empty);
+ if (ret) {
+ pr_err("%s: sps_is_pipe_empty failed with %d\n", __func__, ret);
+ goto no_lpm;
+ }
+
+ /* Stop CONS transfers and go to lpm if no more data in the pipe */
+ if (cons_empty) {
+ if (info.stop && !info.cons_stopped)
+ info.stop(info.start_stop_param,
+ PEER_PERIPHERAL_TO_USB);
+ pr_err("%s: Starting LPM on Bus Suspend\n", __func__);
+ info.cons_stopped = 1;
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ }
+ ipa_suspend_pipes();
+ usb_bam_start_lpm(0);
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+
+no_lpm:
+
+ /* Finish the handshake. Resume Sequence will start automatically
+ by the data in the pipes */
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ mutex_unlock(&info.suspend_resume_mutex);
+}
+
+void usb_bam_finish_suspend_(struct work_struct *w)
+{
+ usb_bam_finish_suspend();
+}
+
static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
@@ -637,14 +824,14 @@
case IPA_RM_RESOURCE_GRANTED:
pr_debug("%s: %s_PROD resource granted\n",
__func__, bam_enable_strings[*cur_bam]);
- cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&prod_avail[*cur_bam]);
+ info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.prod_avail[*cur_bam]);
break;
case IPA_RM_RESOURCE_RELEASED:
pr_debug("%s: %s_PROD resource released\n",
__func__, bam_enable_strings[*cur_bam]);
- cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&prod_released[*cur_bam]);
+ info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.prod_released[*cur_bam]);
break;
default:
break;
@@ -652,18 +839,88 @@
return;
}
+static void usb_bam_resume_hsic_host(void)
+{
+ int i;
+ struct usb_bam_pipe_connect *pipe_iter;
+
+ spin_lock(&usb_bam_lock);
+
+ /* Exit from "full suspend" in case of hsic host */
+ if (hsic_host_dev && info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Getting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_get(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = false;
+
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_iter = &usb_bam_connections[i];
+ if (pipe_iter->bam_type == HSIC_BAM &&
+ pipe_iter->enabled &&
+ pipe_iter->suspended) {
+ spin_unlock(&usb_bam_lock);
+ ipa_resume(pipe_iter->ipa_clnt_hdl);
+ pipe_iter->suspended = false;
+ spin_lock(&usb_bam_lock);
+ }
+ }
+ }
+
+ spin_unlock(&usb_bam_lock);
+}
+
static int cons_request_resource(enum usb_bam cur_bam)
{
+ int ret = -EINPROGRESS;
+
pr_debug("%s: Request %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
- cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&cons_avail[cur_bam]);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.cons_avail[cur_bam]);
- if (ctx.pipes_enabled_per_bam[cur_bam])
- return 0;
+ spin_lock(&usb_bam_lock);
- return -EINPROGRESS;
+ switch (cur_bam) {
+ case HSUSB_BAM:
+ if (ctx.pipes_enabled_per_bam[HSUSB_BAM] &&
+ info.connect_complete &&
+ !info.cons_stopped && !info.prod_stopped) {
+ pr_debug("%s: ACK on cons_request", __func__);
+ ret = 0;
+ } else if (ctx.pipes_enabled_per_bam[HSUSB_BAM] &&
+ info.connect_complete && info.bus_suspend) {
+ info.bus_suspend = 0;
+ if (info.wake_cb)
+ info.wake_cb(info.wake_param);
+ }
+
+ break;
+ case HSIC_BAM:
+ hsic_host_dev_resumed_from_cons_request = true;
+
+ usb_bam_resume_hsic_host();
+
+ /*
+ * Return sucess if there are pipes connected
+ * and not in lpm
+ */
+ if (ctx.pipes_enabled_per_bam[cur_bam] &&
+ !info.in_lpm[cur_bam])
+ ret = 0;
+ break;
+ case SSUSB_BAM:
+ default:
+ break;
+ }
+
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ spin_unlock(&usb_bam_lock);
+
+ if (ret == -EINPROGRESS)
+ pr_debug("%s: EINPROGRESS on cons_request", __func__);
+ return ret;
}
static int usb_cons_request_resource(void)
@@ -681,13 +938,40 @@
pr_debug("%s: Release %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
- cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&cons_released[cur_bam]);
+ info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.cons_released[cur_bam]);
- if (!ctx.pipes_enabled_per_bam[cur_bam])
+ spin_lock(&usb_bam_lock);
+ if (!ctx.pipes_enabled_per_bam[cur_bam]) {
+ spin_unlock(&usb_bam_lock);
+ pr_debug("%s: ACK on cons_release", __func__);
return 0;
+ }
+ spin_unlock(&usb_bam_lock);
- return -EINPROGRESS;
+ if (cur_bam == HSUSB_BAM) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.bus_suspend)
+ queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ pr_debug("%s: EINPROGRESS cons_release", __func__);
+ return -EINPROGRESS;
+ } else if (cur_bam == HSIC_BAM) {
+
+ /*
+ * Allow to go to lpm for now. Actual state will be checked
+ * in msm_bam_hsic_lpm_ok() just before going to lpm.
+ */
+ if (hsic_host_dev && !info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Putting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_put(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = true;
+ }
+ }
+
+ return 0;
}
static int hsic_cons_release_resource(void)
@@ -741,30 +1025,31 @@
}
}
-static void wait_for_prod_granted(enum usb_bam cur_bam)
+static void wait_for_prod_granted(enum usb_bam cur_bam, bool start_cons)
{
int ret;
pr_debug("%s Request %s_PROD_RES\n", __func__,
bam_enable_strings[cur_bam]);
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
pr_debug("%s: CONS already granted for some reason\n",
__func__);
- if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
pr_debug("%s: PROD already granted for some reason\n",
__func__);
- init_completion(&prod_avail[cur_bam]);
- init_completion(&cons_avail[cur_bam]);
+ init_completion(&info.prod_avail[cur_bam]);
+ if (start_cons)
+ init_completion(&info.cons_avail[cur_bam]);
ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
if (!ret) {
- cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&prod_avail[cur_bam]);
+ info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.prod_avail[cur_bam]);
pr_debug("%s: PROD_GRANTED without wait\n", __func__);
} else if (ret == -EINPROGRESS) {
pr_debug("%s: Waiting for PROD_GRANTED\n", __func__);
- if (!wait_for_completion_timeout(&prod_avail[cur_bam],
+ if (!wait_for_completion_timeout(&info.prod_avail[cur_bam],
USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for PROD_GRANTED\n",
__func__);
@@ -772,6 +1057,377 @@
pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
}
+void wait_for_cons_granted(enum usb_bam cur_bam)
+{
+ pr_debug("%s: Waiting for CONS\n", __func__);
+ if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
+ if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout wainting for CONS_REQUEST\n",
+ __func__);
+ pr_err("%s: Finished waiting for CONS\n", __func__);
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.connect_complete = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: CONS is granted\n", __func__);
+
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[HSUSB_BAM]);
+ }
+}
+
+void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params)
+{
+ struct usb_bam_pipe_connect *pipe_connect;
+ enum usb_bam cur_bam;
+ u8 src_idx;
+
+ src_idx = ipa_params->src_idx;
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+
+ wait_for_cons_granted(cur_bam);
+}
+
+static void wait_for_prod_release(enum usb_bam cur_bam)
+{
+ int ret;
+
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s consumer already released\n", __func__);
+ if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s producer already released\n", __func__);
+
+ init_completion(&info.prod_released[cur_bam]);
+ init_completion(&info.cons_released[cur_bam]);
+ pr_debug("%s: Releasing %s_PROD\n", __func__,
+ bam_enable_strings[cur_bam]);
+ ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
+ if (!ret) {
+ pr_debug("%s: Released without waiting\n", __func__);
+ info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.prod_released[cur_bam]);
+ } else if (ret == -EINPROGRESS) {
+ pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
+ if (!wait_for_completion_timeout(&info.prod_released[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout waiting for PROD_RELEASED\n",
+ __func__);
+ } else
+ pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
+}
+
+static int check_pipes_empty(u8 src_idx, u8 dst_idx)
+{
+ struct sps_pipe *prod_pipe, *cons_pipe;
+ u32 prod_empty, cons_empty;
+
+ /* If we have any remaints in the pipes we don't go to sleep */
+ prod_pipe = ctx.usb_bam_sps.sps_pipes[src_idx];
+ cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx];
+ if (sps_is_pipe_empty(prod_pipe, &prod_empty) ||
+ sps_is_pipe_empty(cons_pipe, &cons_empty)) {
+ pr_err("%s: sps_is_pipe_empty failed with\n", __func__);
+ return 0;
+ }
+ if (!prod_empty || !cons_empty) {
+ pr_err("%s: pipes not empty prod=%d cond=%d", __func__,
+ prod_empty, cons_empty);
+ return 0;
+ }
+
+ return 1;
+}
+
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params)
+{
+ struct usb_bam_pipe_connect *pipe_connect;
+ enum usb_bam cur_bam;
+ u8 src_idx, dst_idx;
+
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n", __func__);
+ return;
+ }
+
+ src_idx = ipa_params->src_idx;
+ dst_idx = ipa_params->dst_idx;
+
+ if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index src=%d dst=%d\n",
+ __func__, src_idx, dst_idx);
+ }
+
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+ if (cur_bam != HSUSB_BAM)
+ return;
+
+ info.src_idx = src_idx;
+ info.dst_idx = dst_idx;
+
+ pr_err("%s: Starting suspend sequence(BAM=%s)\n", __func__,
+ bam_enable_strings[cur_bam]);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.bus_suspend = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ /* Stop PROD transfers */
+ if (info.stop) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ /* If cable was disconnected, let disconnection seq do everything */
+ if (info.disconnected) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: Cable disconnected\n", __func__);
+ return;
+ }
+
+ /* Don't go to LPM if data in the pipes */
+ if (!check_pipes_empty(src_idx, dst_idx)) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: pipes not empty, won't start suspend", __func__);
+ return;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ queue_work(ctx.usb_bam_wq, &info.suspend_work);
+}
+
+static void usb_bam_start_suspend(struct work_struct *w)
+{
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ /* If cable was disconnected, let disconnection seq do everything */
+ if (info.disconnected) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: Cable disconnected\n", __func__);
+ return;
+ }
+
+ if (!info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Resume started, not suspending", __func__);
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+
+ /* Stop PROD transfers in case they were started */
+ if (info.stop && !info.prod_stopped) {
+ info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = true;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ /* Don't start LPM seq if data in the pipes */
+ if (!check_pipes_empty(info.src_idx, info.dst_idx)) {
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake[HSUSB_BAM] = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ wait_for_prod_release(HSUSB_BAM);
+
+ mutex_unlock(&info.suspend_resume_mutex);
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_RELEASED)
+ usb_bam_finish_suspend();
+ else
+ pr_debug("Consumer not released yet\n");
+}
+
+static void usb_bam_finish_resume(struct work_struct *w)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+
+ BUG_ON(trans == NULL);
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+ /* Suspend happened in the meantime */
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Bus suspended, not resuming", __func__);
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+ info.lpm_wait_handshake[HSUSB_BAM] = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ wait_for_prod_granted(HSUSB_BAM, true);
+ wait_for_cons_granted(HSUSB_BAM);
+ if (info.cons_stopped) {
+ ipa_resume_pipes();
+ if (info.start) {
+ pr_debug("%s: Enqueue CONS transfer", __func__);
+ info.start(info.start_stop_param,
+ PEER_PERIPHERAL_TO_USB);
+ info.cons_stopped = 0;
+ }
+ }
+
+ if (info.start) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.start(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = false;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[HSUSB_BAM]);
+ }
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: done", __func__);
+}
+
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params)
+{
+ enum usb_bam cur_bam;
+ u8 src_idx, dst_idx;
+ struct usb_bam_pipe_connect *pipe_connect;
+
+ pr_debug("%s: Resuming\n", __func__);
+
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n", __func__);
+ return;
+ }
+
+ src_idx = ipa_params->src_idx;
+ dst_idx = ipa_params->dst_idx;
+
+ if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index src=%d dst=%d\n",
+ __func__, src_idx, dst_idx);
+ return;
+ }
+
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+ if (cur_bam != HSUSB_BAM)
+ return;
+
+ info.in_lpm[HSUSB_BAM] = false;
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.bus_suspend = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ queue_work(ctx.usb_bam_wq, &info.resume_work);
+}
+
+void msm_bam_wait_for_hsic_prod_granted(void)
+{
+ if (hsic_host_dev_resumed_from_cons_request)
+ return;
+
+ ctx.is_bam_inactivity[HSIC_BAM] = false;
+
+ /* Get back to resume state including wakeup ipa */
+ usb_bam_resume_hsic_host();
+
+ /* Ensure getting the producer resource */
+ wait_for_prod_granted(HSIC_BAM, false);
+}
+
+void msm_bam_hsic_notify_on_resume(void)
+{
+ /*
+ * This function is called to notify the usb bam driver
+ * that the hsic core and hsic bam hw are fully resumed
+ * and clocked on. Therefore we can now set the inactivity
+ * timer to the hsic bam hw.
+ */
+ if (ctx.inactivity_timer_ms[HSIC_BAM] &&
+ !hsic_host_dev_resumed_from_cons_request)
+ usb_bam_set_inactivity_timer(HSIC_BAM);
+
+ hsic_host_dev_resumed_from_cons_request = false;
+}
+
+bool msm_bam_hsic_lpm_ok(void)
+{
+ int i;
+ struct usb_bam_pipe_connect *pipe_iter;
+
+ if (hsic_host_dev) {
+
+ pr_debug("%s: Starting hsic full suspend sequence\n",
+ __func__);
+
+ /*
+ * Start low power mode by releasing the device
+ * only in case that indeed the resources were released
+ * and we are still in inactivity state (wake event
+ * have not been occured while we were waiting to the
+ * resources release)
+ */
+ spin_lock(&usb_bam_lock);
+
+ if (info.cur_cons_state[HSIC_BAM] ==
+ IPA_RM_RESOURCE_RELEASED &&
+ info.cur_prod_state[HSIC_BAM] ==
+ IPA_RM_RESOURCE_RELEASED &&
+ ctx.is_bam_inactivity[HSIC_BAM] && info.in_lpm[HSIC_BAM]) {
+
+ /* HSIC host will go now to lpm */
+ pr_debug("%s: vote for suspend hsic %x\n",
+ __func__, (int)hsic_host_dev);
+
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_iter =
+ &usb_bam_connections[i];
+ if (pipe_iter->bam_type == HSIC_BAM &&
+ pipe_iter->enabled &&
+ !pipe_iter->suspended) {
+ spin_unlock(&usb_bam_lock);
+ ipa_suspend(
+ pipe_iter->ipa_clnt_hdl);
+ pipe_iter->suspended = true;
+ spin_lock(&usb_bam_lock);
+ }
+ }
+
+ spin_unlock(&usb_bam_lock);
+ return true;
+ }
+
+ /* We don't allow lpm, therefore renew our vote here */
+ if (info.in_lpm[HSIC_BAM]) {
+ pr_err("%s: Not allow lpm while ref count=0\n",
+ __func__);
+ pr_err("%s: inactivity=%d, c_s=%d p_s=%d lpm=%d\n",
+ __func__, ctx.is_bam_inactivity[HSIC_BAM],
+ info.cur_cons_state[HSIC_BAM],
+ info.cur_prod_state[HSIC_BAM],
+ info.in_lpm[HSIC_BAM]);
+ pm_runtime_get(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = false;
+ spin_unlock(&usb_bam_lock);
+ } else
+ spin_unlock(&usb_bam_lock);
+
+ return false;
+ }
+
+ return true;
+}
+
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx;
@@ -800,53 +1456,86 @@
pipe_connect = &usb_bam_connections[idx];
cur_bam = pipe_connect->bam_type;
- if (cur_bam == HSUSB_BAM) {
- spin_lock(&usb_bam_lock);
- sched_lpm = 0;
- lpm_wait_handshake = 1;
- spin_unlock(&usb_bam_lock);
- }
-
if (pipe_connect->enabled) {
- pr_debug("%s: connection %d was already established\n",
+ pr_err("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
- spin_lock(&usb_bam_lock);
+ pr_debug("%s: enter", __func__);
+
+ if (cur_bam == HSUSB_BAM) {
+ mutex_lock(&info.suspend_resume_mutex);
+
+ spin_lock(&usb_bam_lock);
+ if (ctx.pipes_enabled_per_bam[HSUSB_BAM] == 0) {
+ spin_unlock(&usb_bam_lock);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake[HSUSB_BAM] = true;
+ info.connect_complete = 0;
+ info.disconnected = 0;
+ info.lpm_wait_pipes = 1;
+ info.bus_suspend = 0;
+ info.cons_stopped = 0;
+ info.prod_stopped = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ usb_bam_resume_core(cur_bam);
+ } else
+ spin_unlock(&usb_bam_lock);
+ }
/* Check if BAM requires RESET before connect and reset first pipe */
+ spin_lock(&usb_bam_lock);
if ((pdata->reset_on_connect[cur_bam] == true) &&
- (ctx.pipes_enabled_per_bam[cur_bam] == 0))
- sps_device_reset(ctx.h_bam[cur_bam]);
+ (ctx.pipes_enabled_per_bam[cur_bam] == 0)) {
+ spin_unlock(&usb_bam_lock);
+ sps_device_reset(ctx.h_bam[cur_bam]);
- spin_unlock(&usb_bam_lock);
+ /* On re-connect assume out from lpm for HSIC BAM */
+ if (cur_bam == HSIC_BAM && hsic_host_dev &&
+ info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Getting hsic device %x\n",
+ __func__, (int)hsic_host_dev);
+ pm_runtime_get(hsic_host_dev);
+ }
+
+ /* On re-connect assume out from lpm for all BAMs */
+ info.in_lpm[cur_bam] = false;
+ } else
+ spin_unlock(&usb_bam_lock);
if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
pr_debug("%s: Starting connect sequence\n", __func__);
- wait_for_prod_granted(cur_bam);
+ wait_for_prod_granted(cur_bam, true);
}
ret = connect_pipe_ipa(idx, ipa_params);
if (ret) {
pr_err("%s: pipe connection failure\n", __func__);
+ if (cur_bam == HSUSB_BAM)
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
spin_lock(&usb_bam_lock);
-
pipe_connect->enabled = 1;
+ pipe_connect->suspended = 0;
+
+ /* Set global inactivity timer upon first pipe connection */
+ if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
+ ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
+ pipe_connect->inactivity_notify)
+ usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+
ctx.pipes_enabled_per_bam[cur_bam] += 1;
-
- if (ipa_params->dir == PEER_PERIPHERAL_TO_USB &&
- cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
- pr_debug("%s: Notify CONS_GRANTED\n", __func__);
- ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
- ipa_rm_resource_cons[cur_bam]);
- pr_debug("%s: Ended connect sequence\n", __func__);
- }
-
spin_unlock(&usb_bam_lock);
+ if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
+ wait_for_cons_granted(cur_bam);
+
+ if (cur_bam == HSUSB_BAM)
+ mutex_unlock(&info.suspend_resume_mutex);
+
+ pr_debug("%s: done", __func__);
return 0;
}
@@ -882,7 +1571,7 @@
container_of(w, struct usb_bam_event_info, event_w);
struct usb_bam_pipe_connect *pipe_connect =
container_of(event_info, struct usb_bam_pipe_connect, event);
- struct usb_bam_pipe_connect *pipe_connect_iter;
+ struct usb_bam_pipe_connect *pipe_iter;
int (*callback)(void *priv);
void *param = NULL;
@@ -892,8 +1581,33 @@
pr_debug("%s recieved USB_BAM_EVENT_WAKEUP\n", __func__);
+ /*
+ * Make sure the PROD resource is granted before
+ * wakeup hsic host class driver (done by the callback below)
+ */
+ if (pipe_connect->peer_bam == IPA_P_BAM &&
+ pipe_connect->bam_type == HSIC_BAM &&
+ info.cur_prod_state[HSIC_BAM] != IPA_RM_RESOURCE_GRANTED) {
+ wait_for_prod_granted(HSIC_BAM, false);
+ }
+
+ /*
+ * Check if need to resume the hsic host.
+ * On one hand, since we got the wakeup interrupt
+ * the hsic bam clocks are already enabled, so no need
+ * to actualluy resume the hardware... However, we still need
+ * to update the usb bam driver state (to set in_lpm=false),
+ * and to wake ipa (ipa_resume) and to hold again the hsic host
+ * device again to avoid it going to low poer mode next time
+ * until we complete releasing the hsic consumer and producer
+ * resources against the ipa resource manager.
+ */
+ if (pipe_connect->bam_type == HSIC_BAM)
+ usb_bam_resume_hsic_host();
+
/* Notify about wakeup / activity of the bam */
- event_info->callback(event_info->param);
+ if (event_info->callback)
+ event_info->callback(event_info->param);
/*
* Reset inactivity timer counter if this pipe's bam
@@ -904,6 +1618,16 @@
usb_bam_set_inactivity_timer(pipe_connect->bam_type);
spin_unlock(&usb_bam_lock);
+ if (pipe_connect->bam_type == HSUSB_BAM) {
+ /* A2 wakeup not from LPM (CONS was up) */
+ wait_for_prod_granted(pipe_connect->bam_type, true);
+ if (info.start) {
+ pr_debug("%s: Enqueue PROD transfer", __func__);
+ info.start(info.start_stop_param,
+ USB_TO_PEER_PERIPHERAL);
+ }
+ }
+
break;
case USB_BAM_EVENT_INACTIVITY:
@@ -926,24 +1650,44 @@
*/
spin_lock(&usb_bam_lock);
for (i = 0; i < ctx.max_connections; i++) {
- pipe_connect_iter = &usb_bam_connections[i];
- if (pipe_connect_iter->bam_type ==
+ pipe_iter = &usb_bam_connections[i];
+ if (pipe_iter->bam_type ==
pipe_connect->bam_type &&
- pipe_connect_iter->dir ==
+ pipe_iter->dir ==
PEER_PERIPHERAL_TO_USB &&
- pipe_connect_iter->enabled) {
+ pipe_iter->enabled) {
+ pr_debug("%s: Register wakeup on pipe %x\n",
+ __func__, (int)pipe_iter);
__usb_bam_register_wake_cb(i,
- pipe_connect_iter->activity_notify,
- pipe_connect_iter->priv,
+ pipe_iter->activity_notify,
+ pipe_iter->priv,
false);
}
}
spin_unlock(&usb_bam_lock);
- /* Notify about the inactivity */
+ /* Notify about the inactivity to the USB class driver */
if (callback)
callback(param);
+ wait_for_prod_release(pipe_connect->bam_type);
+ pr_debug("%s: complete wait on hsic producer s=%d\n",
+ __func__, info.cur_prod_state[pipe_connect->bam_type]);
+
+ /*
+ * Allow to go to lpm for now if also consumer is down.
+ * If consumer is up, we will wait to the release consumer
+ * notification.
+ */
+ if (hsic_host_dev &&
+ info.cur_cons_state[HSIC_BAM] ==
+ IPA_RM_RESOURCE_RELEASED && !info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Putting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_put(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = true;
+ }
+
break;
default:
pr_err("%s: unknown usb bam event type %d\n", __func__,
@@ -959,13 +1703,14 @@
container_of(event_info,
struct usb_bam_pipe_connect,
event);
+ enum usb_bam bam = pipe_connect->bam_type;
spin_lock(&usb_bam_lock);
if (event_info->type == USB_BAM_EVENT_WAKEUP_PIPE)
queue_work(ctx.usb_bam_wq, &event_info->event_w);
else if (event_info->type == USB_BAM_EVENT_WAKEUP &&
- ctx.is_bam_inactivity[pipe_connect->bam_type]) {
+ ctx.is_bam_inactivity[bam]) {
/*
* Sps wake event is per pipe, so usb_bam_wake_cb is
@@ -974,7 +1719,8 @@
* Therefore, the first pipe that awaked will be considered
* as global bam wake event.
*/
- ctx.is_bam_inactivity[pipe_connect->bam_type] = false;
+ ctx.is_bam_inactivity[bam] = false;
+
queue_work(ctx.usb_bam_wq, &event_info->event_w);
}
@@ -1111,9 +1857,22 @@
int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param)
{
+ info.wake_cb = callback;
+ info.wake_param = param;
return __usb_bam_register_wake_cb(idx, callback, param, true);
}
+int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param)
+{
+ info.start = start;
+ info.stop = stop;
+ info.start_stop_param = param;
+ return 0;
+}
+
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
{
u32 ret = 0;
@@ -1156,78 +1915,29 @@
return 0;
}
- spin_lock(&usb_bam_lock);
-
ret = disconnect_pipe(idx);
if (ret) {
pr_err("%s: src pipe disconnection failure\n", __func__);
- spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 0;
-
+ spin_lock(&usb_bam_lock);
if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
__func__, pipe_connect->bam_type);
else
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
-
spin_unlock(&usb_bam_lock);
return 0;
}
-static void usb_bam_start_lpm(void)
-{
- struct usb_phy *trans = usb_get_transceiver();
- BUG_ON(trans == NULL);
- spin_lock(&usb_bam_lock);
- lpm_wait_handshake = 0;
- if (sched_lpm) {
- pr_debug("%s: Going to LPM\n", __func__);
- spin_unlock(&usb_bam_lock);
- pm_runtime_resume(trans->dev);
- pm_runtime_put_noidle(trans->dev);
- pm_runtime_suspend(trans->dev);
- return;
- }
- spin_unlock(&usb_bam_lock);
-}
-
-static void wait_for_prod_release(enum usb_bam cur_bam)
-{
- int ret;
-
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
- pr_debug("%s consumer already released\n", __func__);
- if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
- pr_debug("%s producer already released\n", __func__);
-
- init_completion(&prod_released[cur_bam]);
- init_completion(&cons_released[cur_bam]);
- pr_debug("%s: Releasing %s_PROD\n", __func__,
- bam_enable_strings[cur_bam]);
- ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
- if (!ret) {
- pr_debug("%s: Released without waiting\n", __func__);
- cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&prod_released[cur_bam]);
- } else if (ret == -EINPROGRESS) {
- pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
- if (!wait_for_completion_timeout(&prod_released[cur_bam],
- USB_BAM_TIMEOUT))
- pr_err("%s: Timeout waiting for PROD_RELEASED\n",
- __func__);
- } else
- pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
-}
-
static void wait_for_cons_release(enum usb_bam cur_bam)
{
pr_debug("%s: Waiting for CONS release\n", __func__);
- if (cur_prod_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
- if (!wait_for_completion_timeout(&cons_released[cur_bam],
+ if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
+ if (!wait_for_completion_timeout(&info.cons_released[cur_bam],
USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for CONS_RELEASE\n",
__func__);
@@ -1244,26 +1954,40 @@
struct sps_connect *sps_connection;
enum usb_bam cur_bam;
-
if (!ipa_params->prod_clnt_hdl && !ipa_params->cons_clnt_hdl) {
pr_err("%s: Both of the handles is missing\n", __func__);
return -EINVAL;
}
pr_debug("%s: Starting disconnect sequence\n", __func__);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.connect_complete = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ mutex_lock(&info.suspend_resume_mutex);
/* Delay USB core to go into lpm before we finish our handshake */
if (ipa_params->prod_clnt_hdl) {
idx = ipa_params->dst_idx;
pipe_connect = &usb_bam_connections[idx];
+ pipe_connect->activity_notify = NULL;
+ pipe_connect->inactivity_notify = NULL;
+ pipe_connect->priv = NULL;
+
/* Do the release handshake with the A2 via RM */
cur_bam = pipe_connect->bam_type;
+ info.lpm_wait_pipes = 1;
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.disconnected = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
wait_for_prod_release(cur_bam);
/* close USB -> IPA pipe */
+ usb_bam_resume_core(cur_bam);
ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
if (ret) {
pr_err("%s: dst pipe disconnection failure\n",
__func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
@@ -1274,6 +1998,7 @@
if (ret) {
pr_err("%s: failure to disconnect pipe %d\n",
__func__, idx);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
}
@@ -1281,6 +2006,11 @@
if (ipa_params->cons_clnt_hdl) {
idx = ipa_params->src_idx;
pipe_connect = &usb_bam_connections[idx];
+
+ pipe_connect->activity_notify = NULL;
+ pipe_connect->inactivity_notify = NULL;
+ pipe_connect->priv = NULL;
+
cur_bam = pipe_connect->bam_type;
wait_for_cons_release(cur_bam);
/* close IPA -> USB pipe */
@@ -1288,6 +2018,7 @@
if (ret) {
pr_err("%s: src pipe disconnection failure\n",
__func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
@@ -1299,17 +2030,24 @@
if (ret) {
pr_err("%s: failure to disconnect pipe %d\n",
__func__, idx);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
- pr_debug("%s: Notify CONS release\n", __func__);
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pipe_connect->ipa_clnt_hdl = -1;
+
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+ pr_debug("%s Notify CONS _RELEASED\n", __func__);
ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
ipa_rm_resource_cons[cur_bam]);
+ }
pr_debug("%s Ended disconnect sequence\n", __func__);
- usb_bam_start_lpm();
+ usb_bam_start_lpm(1);
+ mutex_unlock(&info.suspend_resume_mutex);
+ return 0;
}
+ mutex_unlock(&info.suspend_resume_mutex);
return 0;
}
EXPORT_SYMBOL(usb_bam_disconnect_ipa);
@@ -1396,9 +2134,11 @@
/*
* Notify inactivity once, Since it is global
- * for all pipes on bam.
+ * for all pipes on bam. Notify only if we have
+ * connected pipes.
*/
- if (pipe_connect->bam_type == bam) {
+ if (pipe_connect->bam_type == bam &&
+ pipe_connect->enabled) {
event_info = &pipe_connect->event;
event_info->type = USB_BAM_EVENT_INACTIVITY;
event_info->param = pipe_connect->priv;
@@ -1630,6 +2370,7 @@
props.num_pipes = pdata->usb_bam_num_pipes;
props.callback = usb_bam_sps_events;
props.user = bam_enable_strings[bam_idx];
+ props.options = SPS_BAM_OPT_IRQ_WAKEUP;
/*
* HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
@@ -1747,7 +2488,8 @@
/* Apply new timer setting if bam has running pipes */
if (ctx.inactivity_timer_ms[bam] != timer_d) {
ctx.inactivity_timer_ms[bam] = timer_d;
- if (ctx.pipes_enabled_per_bam[bam] > 0)
+ if (ctx.pipes_enabled_per_bam[bam] > 0 &&
+ !info.in_lpm[bam])
usb_bam_set_inactivity_timer(bam);
}
@@ -1810,18 +2552,24 @@
ctx.pipes_enabled_per_bam[i] = 0;
ctx.inactivity_timer_ms[i] = 0;
ctx.is_bam_inactivity[i] = false;
- init_completion(&prod_avail[i]);
- complete(&prod_avail[i]);
- init_completion(&cons_avail[i]);
- complete(&cons_avail[i]);
- init_completion(&cons_released[i]);
- complete(&cons_released[i]);
- init_completion(&prod_released[i]);
- complete(&prod_released[i]);
- cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
- cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+ init_completion(&info.prod_avail[i]);
+ complete(&info.prod_avail[i]);
+ init_completion(&info.cons_avail[i]);
+ complete(&info.cons_avail[i]);
+ init_completion(&info.cons_released[i]);
+ complete(&info.cons_released[i]);
+ init_completion(&info.prod_released[i]);
+ complete(&info.prod_released[i]);
+ info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
+ info.cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+ info.lpm_wait_handshake[i] = false;
}
+ INIT_WORK(&info.resume_work, usb_bam_finish_resume);
+ INIT_WORK(&info.suspend_work, usb_bam_start_suspend);
+ INIT_WORK(&info.finish_suspend_work, usb_bam_finish_suspend_);
+ mutex_init(&info.suspend_resume_mutex);
+
spin_lock_init(&usb_bam_peer_handshake_info_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
@@ -1837,8 +2585,8 @@
destroy_workqueue(ctx.usb_bam_wq);
return ret;
}
+ spin_lock_init(&usb_bam_ipa_handshake_info_lock);
usb_bam_ipa_create_resources();
-
spin_lock_init(&usb_bam_lock);
return ret;
@@ -1911,14 +2659,14 @@
bool msm_bam_lpm_ok(void)
{
- spin_lock(&usb_bam_lock);
- if (lpm_wait_handshake) {
- sched_lpm = 1;
- spin_unlock(&usb_bam_lock);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.lpm_wait_handshake[HSUSB_BAM] || info.lpm_wait_pipes) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Scheduling LPM for later\n", __func__);
return 0;
} else {
- spin_unlock(&usb_bam_lock);
+ info.in_lpm[HSUSB_BAM] = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Going to LPM now\n", __func__);
return 1;
}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index eac8953..03aa280 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -229,6 +229,7 @@
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_RESISTANCE,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
@@ -860,21 +861,23 @@
}
/**
- * calculate_cc-
+ * calculate_cc() - converts a hardware coulomb counter reading into uah
* @chip: the bms chip pointer
* @cc: the cc reading from bms h/w
- * @val: return value
- * @coulomb_counter: adjusted coulomb counter for 100%
+ * @clear_cc: whether this function should clear the hardware counter
+ * after reading
*
- * RETURNS: in val pointer coulomb counter based charger in uAh
- * (micro Amp hour)
+ * Converts the 64 bit hardware coulomb counter into microamp-hour by taking
+ * into account hardware resolution and adc errors.
+ *
+ * Return: the coulomb counter based charge in uAh (micro-amp hour)
*/
-static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc)
+static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc, bool clear_cc)
{
struct qpnp_iadc_calib calibration;
struct qpnp_vadc_result result;
int64_t cc_voltage_uv, cc_pvh, cc_uah;
- int ibat_ua, rc;
+ int rc;
rc = qpnp_vadc_read(DIE_TEMP, &result);
if (rc) {
@@ -882,12 +885,6 @@
return chip->software_cc_uah;
}
- rc = get_battery_current(chip, &ibat_ua);
- if (rc) {
- pr_err("could not read battery current: %d\n", rc);
- return chip->software_cc_uah;
- }
-
qpnp_iadc_get_gain_and_offset(&calibration);
pr_debug("cc = %lld, die_temp = %lld\n", cc, result.physical);
cc_voltage_uv = cc_reading_to_uv(cc);
@@ -901,9 +898,14 @@
rc = qpnp_iadc_comp_result(&cc_uah);
if (rc)
pr_debug("error compensation failed: %d\n", rc);
- chip->software_cc_uah += cc_uah;
- reset_cc(chip);
- return (int)chip->software_cc_uah;
+
+ if (clear_cc) {
+ chip->software_cc_uah += cc_uah;
+ reset_cc(chip);
+ return (int)chip->software_cc_uah;
+ } else {
+ return chip->software_cc_uah + cc_uah;
+ }
}
static int get_rbatt(struct qpnp_bms_chip *chip,
@@ -1232,7 +1234,7 @@
pr_debug("ocv_charge_uah = %uuAh\n", params->ocv_charge_uah);
/* calculate cc micro_volt_hour */
- params->cc_uah = calculate_cc(chip, raw->cc);
+ params->cc_uah = calculate_cc(chip, raw->cc, true);
pr_debug("cc_uah = %duAh raw->cc = %llx\n", params->cc_uah, raw->cc);
soc_rbatt = ((params->ocv_charge_uah - params->cc_uah) * 100)
@@ -1242,10 +1244,10 @@
params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
- if (params->rbatt_mohm != chip->rbatt_mohm
- && chip->bms_psy.name != NULL) {
+ if (params->rbatt_mohm != chip->rbatt_mohm) {
chip->rbatt_mohm = params->rbatt_mohm;
- power_supply_changed(&chip->bms_psy);
+ if (chip->bms_psy.name != NULL)
+ power_supply_changed(&chip->bms_psy);
}
calculate_iavg(chip, params->cc_uah, ¶ms->iavg_ua,
@@ -1359,12 +1361,200 @@
module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
+static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
+ int soc)
+{
+ u8 temp;
+ int rc;
+ int iavg_ma = chip->prev_uuc_iavg_ma;
+
+ if (iavg_ma > IAVG_START)
+ temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+ else
+ temp = 0;
+
+ rc = qpnp_write_wrapper(chip, &temp,
+ chip->base + IAVG_STORAGE_REG, 1);
+
+ temp = soc;
+
+ /* don't store soc if temperature is below 5degC */
+ if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+ rc = qpnp_write_wrapper(chip, &temp,
+ chip->base + SOC_STORAGE_REG, 1);
+}
+
+static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
+ int catch_up_sec, int new_soc, int prev_soc)
+{
+ int scaled_soc;
+ int numerator;
+
+ /*
+ * Don't report a high value immediately slowly scale the
+ * value from prev_soc to the new soc based on a charge time
+ * weighted average
+ */
+ pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+ if (catch_up_sec == 0)
+ return new_soc;
+
+ if (chg_time_sec > catch_up_sec)
+ return new_soc;
+
+ numerator = (catch_up_sec - chg_time_sec) * prev_soc
+ + chg_time_sec * new_soc;
+ scaled_soc = numerator / catch_up_sec;
+
+ pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
+ chg_time_sec, new_soc, prev_soc, scaled_soc);
+
+ return scaled_soc;
+}
+
+/*
+ * bms_fake_battery is set in setups where a battery emulator is used instead
+ * of a real battery. This makes the bms driver report a different/fake value
+ * regardless of the calculated state of charge.
+ */
+static int bms_fake_battery = -EINVAL;
+module_param(bms_fake_battery, int, 0644);
+
+static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
+{
+ pr_debug("Reported voltage based soc = %d\n",
+ chip->prev_voltage_based_soc);
+ return chip->prev_voltage_based_soc;
+}
+
+#define SOC_CATCHUP_SEC_MAX 600
+#define SOC_CATCHUP_SEC_PER_PERCENT 60
+#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT)
+#define SOC_CHANGE_PER_SEC 20
+static int report_cc_based_soc(struct qpnp_bms_chip *chip)
+{
+ int soc, soc_change;
+ int time_since_last_change_sec, charge_time_sec = 0;
+ unsigned long last_change_sec;
+ struct timespec now;
+ struct qpnp_vadc_result result;
+ int batt_temp;
+ int rc;
+ bool charging, charging_since_last_report;
+
+ soc = chip->calculated_soc;
+
+ rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ LR_MUX1_BATT_THERM, rc);
+ return rc;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_soc_mutex);
+ last_change_sec = chip->last_soc_change_sec;
+ calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
+
+ charging = is_battery_charging(chip);
+ charging_since_last_report = charging || (chip->last_soc_unbound
+ && chip->was_charging_at_sleep);
+ /*
+ * account for charge time - limit it to SOC_CATCHUP_SEC to
+ * avoid overflows when charging continues for extended periods
+ */
+ if (charging) {
+ if (chip->charge_start_tm_sec == 0) {
+ /*
+ * calculating soc for the first time
+ * after start of chg. Initialize catchup time
+ */
+ if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
+ chip->catch_up_time_sec =
+ (soc - chip->last_soc)
+ * SOC_CATCHUP_SEC_PER_PERCENT;
+ else
+ chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
+
+ if (chip->catch_up_time_sec < 0)
+ chip->catch_up_time_sec = 0;
+ chip->charge_start_tm_sec = last_change_sec;
+ }
+
+ charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
+ - chip->charge_start_tm_sec);
+
+ /* end catchup if calculated soc and last soc are same */
+ if (chip->last_soc == soc)
+ chip->catch_up_time_sec = 0;
+ }
+
+ if (chip->last_soc != -EINVAL) {
+ /*
+ * last_soc < soc ... if we have not been charging at all
+ * since the last time this was called, report previous SoC.
+ * Otherwise, scale and catch up.
+ */
+ if (chip->last_soc < soc && !charging_since_last_report)
+ soc = chip->last_soc;
+ else if (chip->last_soc < soc && soc != 100)
+ soc = scale_soc_while_chg(chip, charge_time_sec,
+ chip->catch_up_time_sec,
+ soc, chip->last_soc);
+
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec / SOC_CHANGE_PER_SEC);
+ if (chip->last_soc_unbound) {
+ chip->last_soc_unbound = false;
+ } else {
+ /*
+ * if soc have not been unbound by resume,
+ * only change reported SoC by 1.
+ */
+ soc_change = min(1, soc_change);
+ }
+
+ if (soc < chip->last_soc && soc != 0)
+ soc = chip->last_soc - soc_change;
+ if (soc > chip->last_soc && soc != 100)
+ soc = chip->last_soc + soc_change;
+ }
+
+ if (chip->last_soc != soc)
+ chip->last_soc_change_sec = last_change_sec;
+
+ pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
+ chip->last_soc, chip->calculated_soc,
+ soc, time_since_last_change_sec);
+ chip->last_soc = bound_soc(soc);
+ backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
+ pr_debug("Reported SOC = %d\n", chip->last_soc);
+ chip->t_soc_queried = now;
+ mutex_unlock(&chip->last_soc_mutex);
+
+ return soc;
+}
+
+static int report_state_of_charge(struct qpnp_bms_chip *chip)
+{
+ if (bms_fake_battery != -EINVAL) {
+ pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+ return bms_fake_battery;
+ } else if (chip->use_voltage_soc)
+ return report_voltage_based_soc(chip);
+ else
+ return report_cc_based_soc(chip);
+}
+
#define VBATT_ERROR_MARGIN 20000
static int charging_adjustments(struct qpnp_bms_chip *chip,
struct soc_params *params, int soc,
int vbat_uv, int ibat_ua, int batt_temp)
{
- int chg_soc, batt_terminal_uv;
+ int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
batt_terminal_uv = vbat_uv + VBATT_ERROR_MARGIN
+ (ibat_ua * chip->r_conn_mohm) / 1000;
@@ -1402,10 +1592,16 @@
return chip->prev_chg_soc;
}
- chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
+ soc_ibat = bound_soc(linear_interpolate(chip->soc_at_cv,
+ chip->ibat_at_cv_ua,
100, -1 * chip->chg_term_ua,
- ibat_ua);
- chg_soc = bound_soc(chg_soc);
+ ibat_ua));
+ weight_ibat = bound_soc(linear_interpolate(1, chip->soc_at_cv,
+ 100, 100, chip->prev_chg_soc));
+ weight_cc = 100 - weight_ibat;
+ chg_soc = bound_soc((soc_ibat * weight_ibat + weight_cc * soc)/100);
+ pr_debug("weight_ibat = %d, weight_cc = %d, soc_ibat = %d, soc_cc = %d\n",
+ weight_ibat, weight_cc, soc_ibat, soc);
/* always report a higher soc */
if (chg_soc > chip->prev_chg_soc) {
@@ -1736,12 +1932,6 @@
new_calculated_soc);
done_calculating:
- if (new_calculated_soc != chip->calculated_soc
- && chip->bms_psy.name != NULL) {
- power_supply_changed(&chip->bms_psy);
- pr_debug("power supply changed\n");
- }
-
chip->calculated_soc = new_calculated_soc;
pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
mutex_lock(&chip->last_soc_mutex);
@@ -1765,6 +1955,20 @@
params.delta_time_s);
}
mutex_unlock(&chip->last_soc_mutex);
+
+ if (new_calculated_soc != chip->calculated_soc
+ && chip->bms_psy.name != NULL) {
+ power_supply_changed(&chip->bms_psy);
+ pr_debug("power supply changed\n");
+ } else {
+ /*
+ * Call report state of charge anyways to periodically update
+ * reported SoC. This prevents reported SoC from being stuck
+ * when calculated soc doesn't change.
+ */
+ report_state_of_charge(chip);
+ }
+
get_current_time(&chip->last_recalc_time);
chip->first_time_calc_soc = 0;
return chip->calculated_soc;
@@ -1861,196 +2065,6 @@
(chip->calculate_soc_ms)));
}
-static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
- int soc)
-{
- u8 temp;
- int rc;
- int iavg_ma = chip->prev_uuc_iavg_ma;
-
- if (iavg_ma > IAVG_START)
- temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
- else
- temp = 0;
-
- rc = qpnp_write_wrapper(chip, &temp,
- chip->base + IAVG_STORAGE_REG, 1);
-
- temp = soc;
-
- /* don't store soc if temperature is below 5degC */
- if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
- rc = qpnp_write_wrapper(chip, &temp,
- chip->base + SOC_STORAGE_REG, 1);
-}
-
-#define SOC_CATCHUP_SEC_MAX 600
-#define SOC_CATCHUP_SEC_PER_PERCENT 60
-#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
-static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
- int catch_up_sec, int new_soc, int prev_soc)
-{
- int scaled_soc;
- int numerator;
-
- /*
- * Don't report a high value immediately slowly scale the
- * value from prev_soc to the new soc based on a charge time
- * weighted average
- */
- pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
- if (catch_up_sec == 0)
- return new_soc;
- /*
- * if charging for more than catch_up time, simply return
- * new soc
- */
- if (chg_time_sec > catch_up_sec)
- return new_soc;
-
- numerator = (catch_up_sec - chg_time_sec) * prev_soc
- + chg_time_sec * new_soc;
- scaled_soc = numerator / catch_up_sec;
-
- pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
- chg_time_sec, new_soc, prev_soc, scaled_soc);
-
- return scaled_soc;
-}
-
-/*
- * bms_fake_battery is set in setups where a battery emulator is used instead
- * of a real battery. This makes the bms driver report a different/fake value
- * regardless of the calculated state of charge.
- */
-static int bms_fake_battery = -EINVAL;
-module_param(bms_fake_battery, int, 0644);
-
-static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
-{
- pr_debug("Reported voltage based soc = %d\n",
- chip->prev_voltage_based_soc);
- return chip->prev_voltage_based_soc;
-}
-
-#define SOC_CHANGE_PER_SEC 20
-static int report_cc_based_soc(struct qpnp_bms_chip *chip)
-{
- int soc, soc_change;
- int time_since_last_change_sec, charge_time_sec = 0;
- unsigned long last_change_sec;
- struct timespec now;
- struct qpnp_vadc_result result;
- int batt_temp;
- int rc;
- bool charging, charging_since_last_report;
-
- soc = chip->calculated_soc;
-
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
-
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- LR_MUX1_BATT_THERM, rc);
- return rc;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
- result.measurement);
- batt_temp = (int)result.physical;
-
- mutex_lock(&chip->last_soc_mutex);
- last_change_sec = chip->last_soc_change_sec;
- calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
-
- charging = is_battery_charging(chip);
- charging_since_last_report = charging || (chip->last_soc_unbound
- && chip->was_charging_at_sleep);
- /*
- * account for charge time - limit it to SOC_CATCHUP_SEC to
- * avoid overflows when charging continues for extended periods
- */
- if (charging) {
- if (chip->charge_start_tm_sec == 0) {
- /*
- * calculating soc for the first time
- * after start of chg. Initialize catchup time
- */
- if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
- chip->catch_up_time_sec =
- (soc - chip->last_soc)
- * SOC_CATCHUP_SEC_PER_PERCENT;
- else
- chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
-
- if (chip->catch_up_time_sec < 0)
- chip->catch_up_time_sec = 0;
- chip->charge_start_tm_sec = last_change_sec;
- }
-
- charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
- - chip->charge_start_tm_sec);
-
- /* end catchup if calculated soc and last soc are same */
- if (chip->last_soc == soc)
- chip->catch_up_time_sec = 0;
- }
-
- if (chip->last_soc != -EINVAL) {
- /* last_soc < soc ... if we have not been charging at all
- * since the last time this was called, report previous SoC.
- * Otherwise, scale and catch up.
- */
- if (chip->last_soc < soc && !charging_since_last_report)
- soc = chip->last_soc;
- else if (chip->last_soc < soc && soc != 100)
- soc = scale_soc_while_chg(chip, charge_time_sec,
- chip->catch_up_time_sec,
- soc, chip->last_soc);
-
- soc_change = min((int)abs(chip->last_soc - soc),
- time_since_last_change_sec / SOC_CHANGE_PER_SEC);
- if (chip->last_soc_unbound) {
- chip->last_soc_unbound = false;
- } else {
- /*
- * if soc have not been unbound by resume,
- * only change reported SoC by 1.
- */
- soc_change = min(1, soc_change);
- }
-
- if (soc < chip->last_soc && soc != 0)
- soc = chip->last_soc - soc_change;
- if (soc > chip->last_soc && soc != 100)
- soc = chip->last_soc + soc_change;
- }
-
- if (chip->last_soc != soc)
- chip->last_soc_change_sec = last_change_sec;
-
- pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
- chip->last_soc, chip->calculated_soc,
- soc, time_since_last_change_sec);
- chip->last_soc = bound_soc(soc);
- backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
- pr_debug("Reported SOC = %d\n", chip->last_soc);
- chip->t_soc_queried = now;
- mutex_unlock(&chip->last_soc_mutex);
-
- return soc;
-}
-
-static int report_state_of_charge(struct qpnp_bms_chip *chip)
-{
- if (bms_fake_battery != -EINVAL) {
- pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
- return bms_fake_battery;
- } else if (chip->use_voltage_soc)
- return report_voltage_based_soc(chip);
- else
- return report_cc_based_soc(chip);
-}
-
static void configure_vbat_monitor_low(struct qpnp_bms_chip *chip)
{
mutex_lock(&chip->vbat_monitor_mutex);
@@ -2269,8 +2283,10 @@
mutex_lock(&chip->last_ocv_uv_mutex);
chip->soc_at_cv = -EINVAL;
chip->prev_chg_soc = -EINVAL;
- if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL)
+ if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
chip->done_charging = true;
+ chip->last_soc_invalid = true;
+ }
mutex_unlock(&chip->last_ocv_uv_mutex);
}
@@ -2341,6 +2357,20 @@
return result_ua;
}
+/* Returns coulomb counter in uAh */
+static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
+{
+ int64_t cc_raw;
+
+ mutex_lock(&chip->bms_output_lock);
+ lock_output_data(chip);
+ read_cc_raw(chip, &cc_raw);
+ unlock_output_data(chip);
+ mutex_unlock(&chip->bms_output_lock);
+
+ return calculate_cc(chip, cc_raw, false);
+}
+
/* Returns full charge design in uAh */
static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
{
@@ -2373,6 +2403,9 @@
case POWER_SUPPLY_PROP_RESISTANCE:
val->intval = get_prop_bms_batt_resistance(chip);
break;
+ case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+ val->intval = get_prop_bms_charge_counter(chip);
+ break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
@@ -2503,6 +2536,8 @@
batt_data = &palladium_1500_data;
} else if (chip->batt_type == BATT_OEM) {
batt_data = &oem_batt_data;
+ } else if (chip->batt_type == BATT_QRD_4V35_2000MAH) {
+ batt_data = &QRD_4v35_2000mAh_data;
} else {
battery_id = read_battery_id(chip);
if (battery_id < 0) {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 3d8a75d..a5da421 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -25,6 +25,9 @@
#include <linux/power_supply.h>
#include <linux/bitops.h>
#include <linux/ratelimit.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
/* Interrupt offsets */
#define INT_RT_STS(base) (base + 0x10)
@@ -91,8 +94,13 @@
#define BUCK_TEST_SMBC_MODES 0xE6
#define SEC_ACCESS 0xD0
#define BAT_IF_VREF_BAT_THM_CTRL 0x4A
+#define BAT_IF_BPD_CTRL 0x48
+#define BOOST_VSET 0x41
+#define BOOST_ENABLE_CONTROL 0x46
+#define COMP_OVR1 0xEA
#define REG_OFFSET_PERP_SUBTYPE 0x05
+
/* SMBB peripheral subtype values */
#define SMBB_CHGR_SUBTYPE 0x01
#define SMBB_BUCK_SUBTYPE 0x02
@@ -126,7 +134,12 @@
#define USB_VALID_DEB_20MS 0x03
#define BUCK_VBAT_REG_NODE_SEL_BIT BIT(0)
#define VREF_BATT_THERM_FORCE_ON 0xC0
+#define BAT_IF_BPD_CTRL_SEL 0x03
#define VREF_BAT_THM_ENABLED_FSM 0x80
+#define REV_BST_DETECTED BIT(0)
+#define BAT_THM_EN BIT(1)
+#define BAT_ID_EN BIT(0)
+#define BOOST_PWR_EN BIT(7)
/* Interrupt definitions */
/* smbb_chg_interrupts */
@@ -178,6 +191,17 @@
/* Workaround flags */
#define CHG_FLAGS_VCP_WA BIT(0)
+#define BOOST_FLASH_WA BIT(1)
+
+struct qpnp_chg_irq {
+ unsigned int irq;
+ unsigned long disabled;
+};
+
+struct qpnp_chg_regulator {
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+};
/**
* struct qpnp_chg_chip - device information
@@ -237,14 +261,14 @@
u16 boost_base;
u16 misc_base;
u16 freq_base;
- unsigned int usbin_valid_irq;
- unsigned int dcin_valid_irq;
- unsigned int chg_gone_irq;
- unsigned int chg_fastchg_irq;
- unsigned int chg_trklchg_irq;
- unsigned int chg_failed_irq;
- unsigned int chg_vbatdet_lo_irq;
- unsigned int batt_pres_irq;
+ struct qpnp_chg_irq usbin_valid;
+ struct qpnp_chg_irq dcin_valid;
+ struct qpnp_chg_irq chg_gone;
+ struct qpnp_chg_irq chg_fastchg;
+ struct qpnp_chg_irq chg_trklchg;
+ struct qpnp_chg_irq chg_failed;
+ struct qpnp_chg_irq chg_vbatdet_lo;
+ struct qpnp_chg_irq batt_pres;
bool bat_is_cool;
bool bat_is_warm;
bool chg_done;
@@ -253,6 +277,8 @@
bool batt_present;
bool charging_disabled;
bool use_default_batt_values;
+ bool duty_cycle_100p;
+ unsigned int bpd_detection;
unsigned int max_bat_chg_current;
unsigned int warm_bat_chg_ma;
unsigned int cool_bat_chg_ma;
@@ -284,13 +310,35 @@
struct delayed_work arb_stop_work;
struct delayed_work eoc_work;
struct wake_lock eoc_wake_lock;
+ struct qpnp_chg_regulator otg_vreg;
+ struct qpnp_chg_regulator boost_vreg;
};
+
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
{}
};
+#define BPD_MAX 3
+
+static const char *bpd_list[BPD_MAX] = {
+ "bpd_thm",
+ "bpd_id",
+ "bpd_thm_id",
+};
+
+static inline int
+get_bpd(const char *name)
+{
+ int i = 0;
+ for (i = 0 ; i < BPD_MAX; i++) {
+ if (strcmp(name, bpd_list[i]) == 0)
+ return i;
+ }
+ return -EINVAL;
+}
+
static int
qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
u16 base, int count)
@@ -354,6 +402,24 @@
return 0;
}
+static void
+qpnp_chg_enable_irq(struct qpnp_chg_irq *irq)
+{
+ if (__test_and_clear_bit(0, &irq->disabled)) {
+ pr_debug("number = %d\n", irq->irq);
+ enable_irq(irq->irq);
+ }
+}
+
+static void
+qpnp_chg_disable_irq(struct qpnp_chg_irq *irq)
+{
+ if (!__test_and_set_bit(0, &irq->disabled)) {
+ pr_debug("number = %d\n", irq->irq);
+ disable_irq_nosync(irq->irq);
+ }
+}
+
#define USB_OTG_EN_BIT BIT(0)
static int
qpnp_chg_is_otg_en_set(struct qpnp_chg_chip *chip)
@@ -376,6 +442,25 @@
}
static int
+qpnp_chg_is_boost_en_set(struct qpnp_chg_chip *chip)
+{
+ u8 boost_en_ctl;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &boost_en_ctl,
+ chip->boost_base + BOOST_ENABLE_CONTROL, 1);
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ chip->boost_base + BOOST_ENABLE_CONTROL, rc);
+ return rc;
+ }
+
+ pr_debug("boost en 0x%x\n", boost_en_ctl);
+
+ return (boost_en_ctl & BOOST_PWR_EN) ? 1 : 0;
+}
+
+static int
qpnp_chg_is_batt_present(struct qpnp_chg_chip *chip)
{
u8 batt_pres_rt_sts;
@@ -561,6 +646,32 @@
disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
}
+#define BUCK_DUTY_MASK_100P 0x30
+static int
+qpnp_buck_set_100_duty_cycle_enable(struct qpnp_chg_chip *chip, int enable)
+{
+ int rc;
+
+ pr_debug("enable: %d\n", enable);
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + SEC_ACCESS, 0xA5, 0xA5, 1);
+ if (rc) {
+ pr_debug("failed to write sec access rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + BUCK_TEST_SMBC_MODES,
+ BUCK_DUTY_MASK_100P, enable ? 0x00 : 0x10, 1);
+ if (rc) {
+ pr_debug("failed enable 100p duty cycle rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
#define COMPATATOR_OVERRIDE_0 0x80
static int
qpnp_chg_toggle_chg_done_logic(struct qpnp_chg_chip *chip, int enable)
@@ -649,14 +760,16 @@
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
wake_lock(&chip->eoc_wake_lock);
- disable_irq_nosync(chip->chg_vbatdet_lo_irq);
+ qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
} else {
qpnp_chg_charge_en(chip, !chip->charging_disabled);
}
power_supply_changed(chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
- power_supply_changed(&chip->batt_psy);
+ if (chip->dc_chgpth_base)
+ power_supply_changed(&chip->dc_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
return IRQ_HANDLED;
}
@@ -771,9 +884,11 @@
if (rc)
pr_err("Failed to write chg_fail clear bit!\n");
- power_supply_changed(&chip->batt_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
power_supply_changed(chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
+ if (chip->dc_chgpth_base)
+ power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
@@ -785,7 +900,8 @@
pr_debug("TRKL IRQ triggered\n");
chip->chg_done = false;
- power_supply_changed(&chip->batt_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
return IRQ_HANDLED;
}
@@ -797,10 +913,12 @@
pr_debug("FAST_CHG IRQ triggered\n");
chip->chg_done = false;
- power_supply_changed(&chip->batt_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
power_supply_changed(chip->usb_psy);
- power_supply_changed(&chip->dc_psy);
- enable_irq(chip->chg_vbatdet_lo_irq);
+ if (chip->dc_chgpth_base)
+ power_supply_changed(&chip->dc_psy);
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
return IRQ_HANDLED;
}
@@ -1097,7 +1215,6 @@
get_prop_capacity(struct qpnp_chg_chip *chip)
{
union power_supply_propval ret = {0,};
- bool usb_online, dc_online;
if (chip->use_default_batt_values || !get_prop_batt_present(chip))
return DEFAULT_CAPACITY;
@@ -1106,11 +1223,8 @@
chip->bms_psy->get_property(chip->bms_psy,
POWER_SUPPLY_PROP_CAPACITY, &ret);
if (ret.intval == 0) {
- usb_online = chip->usb_psy->get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_ONLINE, &ret);
- dc_online = chip->dc_psy.get_property(&chip->dc_psy,
- POWER_SUPPLY_PROP_ONLINE, &ret);
- if (!usb_online && !dc_online)
+ if (!qpnp_chg_is_usb_chg_plugged_in(chip)
+ && !qpnp_chg_is_usb_chg_plugged_in(chip))
pr_warn_ratelimited("Battery 0, CHG absent\n");
}
return ret.intval;
@@ -1163,21 +1277,6 @@
chip->bms_psy = power_supply_get_by_name("bms");
chip->usb_psy->get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_SCOPE, &ret);
- if (ret.intval) {
- if ((ret.intval == POWER_SUPPLY_SCOPE_SYSTEM)
- && !qpnp_chg_is_otg_en_set(chip)) {
- switch_usb_to_host_mode(chip);
- return;
- }
- if ((ret.intval == POWER_SUPPLY_SCOPE_DEVICE)
- && qpnp_chg_is_otg_en_set(chip)) {
- switch_usb_to_charge_mode(chip);
- return;
- }
- }
-
- chip->usb_psy->get_property(chip->usb_psy,
POWER_SUPPLY_PROP_ONLINE, &ret);
/* Only honour requests while USB is present */
@@ -1405,6 +1504,48 @@
return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
}
+#define BOOST_MIN_UV 4200000
+#define BOOST_MAX_UV 5500000
+#define BOOST_STEP_UV 50000
+#define BOOST_MIN 16
+#define N_BOOST_V ((BOOST_MAX_UV - BOOST_MIN_UV) / BOOST_STEP_UV + 1)
+static int
+qpnp_boost_vset(struct qpnp_chg_chip *chip, int voltage)
+{
+ u8 reg = 0;
+
+ if (voltage < BOOST_MIN_UV || voltage > BOOST_MAX_UV) {
+ pr_err("invalid voltage requested %d uV\n", voltage);
+ return -EINVAL;
+ }
+
+ reg = DIV_ROUND_UP(voltage - BOOST_MIN_UV, BOOST_STEP_UV) + BOOST_MIN;
+
+ pr_debug("voltage=%d setting %02x\n", voltage, reg);
+ return qpnp_chg_write(chip, ®, chip->boost_base + BOOST_VSET, 1);
+}
+
+static int
+qpnp_boost_vget_uv(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 boost_reg;
+
+ rc = qpnp_chg_read(chip, &boost_reg,
+ chip->boost_base + BOOST_VSET, 1);
+ if (rc) {
+ pr_err("failed to read BOOST_VSET rc=%d\n", rc);
+ return rc;
+ }
+
+ if (boost_reg < BOOST_MIN) {
+ pr_err("Invalid reading from 0x%x\n", boost_reg);
+ return -EINVAL;
+ }
+
+ return BOOST_MIN_UV + ((boost_reg - BOOST_MIN) * BOOST_STEP_UV);
+}
+
/* JEITA compliance logic */
static void
qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -1467,6 +1608,228 @@
}
}
+/* OTG regulator operations */
+static int
+qpnp_chg_regulator_otg_enable(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+ return switch_usb_to_host_mode(chip);
+}
+
+static int
+qpnp_chg_regulator_otg_disable(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+ return switch_usb_to_charge_mode(chip);
+}
+
+static int
+qpnp_chg_regulator_otg_is_enabled(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+ return qpnp_chg_is_otg_en_set(chip);
+}
+
+static int
+qpnp_chg_regulator_boost_enable(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+ int rc;
+
+ if (qpnp_chg_is_usb_chg_plugged_in(chip) &&
+ (chip->flags & BOOST_FLASH_WA)) {
+ qpnp_chg_usb_suspend_enable(chip, 1);
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + SEC_ACCESS,
+ 0xFF,
+ 0xA5, 1);
+ if (rc) {
+ pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + COMP_OVR1,
+ 0xFF,
+ 0x2F, 1);
+ if (rc) {
+ pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return qpnp_chg_masked_write(chip,
+ chip->boost_base + BOOST_ENABLE_CONTROL,
+ BOOST_PWR_EN,
+ BOOST_PWR_EN, 1);
+}
+
+/* Boost regulator operations */
+#define ABOVE_VBAT_WEAK BIT(1)
+static int
+qpnp_chg_regulator_boost_disable(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+ int rc;
+ u8 vbat_sts;
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->boost_base + BOOST_ENABLE_CONTROL,
+ BOOST_PWR_EN,
+ 0, 1);
+ if (rc) {
+ pr_err("failed to disable boost rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_read(chip, &vbat_sts,
+ chip->chgr_base + CHGR_VBAT_STATUS, 1);
+ if (rc) {
+ pr_err("failed to read bat sts rc=%d\n", rc);
+ return rc;
+ }
+
+ if (!(vbat_sts & ABOVE_VBAT_WEAK) && (chip->flags & BOOST_FLASH_WA)) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + SEC_ACCESS,
+ 0xFF,
+ 0xA5, 1);
+ if (rc) {
+ pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + COMP_OVR1,
+ 0xFF,
+ 0x20, 1);
+ if (rc) {
+ pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+ return rc;
+ }
+
+ usleep(2000);
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + SEC_ACCESS,
+ 0xFF,
+ 0xA5, 1);
+ if (rc) {
+ pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + COMP_OVR1,
+ 0xFF,
+ 0x00, 1);
+ if (rc) {
+ pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (qpnp_chg_is_usb_chg_plugged_in(chip)
+ && (chip->flags & BOOST_FLASH_WA)) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + SEC_ACCESS,
+ 0xFF,
+ 0xA5, 1);
+ if (rc) {
+ pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + COMP_OVR1,
+ 0xFF,
+ 0x00, 1);
+ if (rc) {
+ pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+ return rc;
+ }
+
+ usleep(1000);
+
+ qpnp_chg_usb_suspend_enable(chip, 0);
+ }
+
+ return rc;
+}
+
+static int
+qpnp_chg_regulator_boost_is_enabled(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+ return qpnp_chg_is_boost_en_set(chip);
+}
+
+static int
+qpnp_chg_regulator_boost_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ int uV = min_uV;
+ int rc;
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+ if (uV < BOOST_MIN_UV && max_uV >= BOOST_MIN_UV)
+ uV = BOOST_MIN_UV;
+
+
+ if (uV < BOOST_MIN_UV || uV > BOOST_MAX_UV) {
+ pr_err("request %d uV is out of bounds\n", uV);
+ return -EINVAL;
+ }
+
+ *selector = DIV_ROUND_UP(uV - BOOST_MIN_UV, BOOST_STEP_UV);
+ if ((*selector * BOOST_STEP_UV + BOOST_MIN_UV) > max_uV) {
+ pr_err("no available setpoint [%d, %d] uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ rc = qpnp_boost_vset(chip, uV);
+
+ return rc;
+}
+
+static int
+qpnp_chg_regulator_boost_get_voltage(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+ return qpnp_boost_vget_uv(chip);
+}
+
+static int
+qpnp_chg_regulator_boost_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector >= N_BOOST_V)
+ return 0;
+
+ return BOOST_MIN_UV + (selector * BOOST_STEP_UV);
+}
+
+static struct regulator_ops qpnp_chg_otg_reg_ops = {
+ .enable = qpnp_chg_regulator_otg_enable,
+ .disable = qpnp_chg_regulator_otg_disable,
+ .is_enabled = qpnp_chg_regulator_otg_is_enabled,
+};
+
+static struct regulator_ops qpnp_chg_boost_reg_ops = {
+ .enable = qpnp_chg_regulator_boost_enable,
+ .disable = qpnp_chg_regulator_boost_disable,
+ .is_enabled = qpnp_chg_regulator_boost_is_enabled,
+ .set_voltage = qpnp_chg_regulator_boost_set_voltage,
+ .get_voltage = qpnp_chg_regulator_boost_get_voltage,
+ .list_voltage = qpnp_chg_regulator_boost_list_voltage,
+};
+
#define CONSECUTIVE_COUNT 3
static void
qpnp_eoc_work(struct work_struct *work)
@@ -1523,7 +1886,7 @@
qpnp_chg_charge_en(chip, 0);
chip->chg_done = true;
power_supply_changed(&chip->batt_psy);
- enable_irq(chip->chg_vbatdet_lo_irq);
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
goto stop_eoc;
} else {
count += 1;
@@ -1532,7 +1895,7 @@
} else if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
(chip->max_voltage_mv - chip->resume_delta_mv))) {
pr_debug("woke up too early\n");
- enable_irq(chip->chg_vbatdet_lo_irq);
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
goto stop_eoc;
}
} else {
@@ -1653,6 +2016,8 @@
{
if (chip->revision > 0 && chip->type == SMBB)
chip->flags |= CHG_FLAGS_VCP_WA;
+ if (chip->type == SMBB)
+ chip->flags |= BOOST_FLASH_WA;
}
static int
@@ -1689,157 +2054,157 @@
case SMBB_CHGR_SUBTYPE:
case SMBBP_CHGR_SUBTYPE:
case SMBCL_CHGR_SUBTYPE:
- chip->chg_fastchg_irq = spmi_get_irq_byname(spmi,
+ chip->chg_fastchg.irq = spmi_get_irq_byname(spmi,
spmi_resource, "fast-chg-on");
- if (chip->chg_fastchg_irq < 0) {
+ if (chip->chg_fastchg.irq < 0) {
pr_err("Unable to get fast-chg-on irq\n");
return rc;
}
- chip->chg_trklchg_irq = spmi_get_irq_byname(spmi,
+ chip->chg_trklchg.irq = spmi_get_irq_byname(spmi,
spmi_resource, "trkl-chg-on");
- if (chip->chg_trklchg_irq < 0) {
+ if (chip->chg_trklchg.irq < 0) {
pr_err("Unable to get trkl-chg-on irq\n");
return rc;
}
- chip->chg_failed_irq = spmi_get_irq_byname(spmi,
+ chip->chg_failed.irq = spmi_get_irq_byname(spmi,
spmi_resource, "chg-failed");
- if (chip->chg_failed_irq < 0) {
+ if (chip->chg_failed.irq < 0) {
pr_err("Unable to get chg_failed irq\n");
return rc;
}
- chip->chg_vbatdet_lo_irq = spmi_get_irq_byname(spmi,
+ chip->chg_vbatdet_lo.irq = spmi_get_irq_byname(spmi,
spmi_resource, "vbat-det-lo");
- if (chip->chg_vbatdet_lo_irq < 0) {
+ if (chip->chg_vbatdet_lo.irq < 0) {
pr_err("Unable to get fast-chg-on irq\n");
return rc;
}
- rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
+ rc |= devm_request_irq(chip->dev, chip->chg_failed.irq,
qpnp_chg_chgr_chg_failed_irq_handler,
IRQF_TRIGGER_RISING, "chg-failed", chip);
if (rc < 0) {
pr_err("Can't request %d chg-failed: %d\n",
- chip->chg_failed_irq, rc);
+ chip->chg_failed.irq, rc);
return rc;
}
- rc |= devm_request_irq(chip->dev, chip->chg_fastchg_irq,
+ rc |= devm_request_irq(chip->dev, chip->chg_fastchg.irq,
qpnp_chg_chgr_chg_fastchg_irq_handler,
IRQF_TRIGGER_RISING,
"fast-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d fast-chg-on: %d\n",
- chip->chg_fastchg_irq, rc);
+ chip->chg_fastchg.irq, rc);
return rc;
}
- rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
+ rc |= devm_request_irq(chip->dev, chip->chg_trklchg.irq,
qpnp_chg_chgr_chg_trklchg_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"trkl-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d trkl-chg-on: %d\n",
- chip->chg_trklchg_irq, rc);
+ chip->chg_trklchg.irq, rc);
return rc;
}
rc |= devm_request_irq(chip->dev,
- chip->chg_vbatdet_lo_irq,
+ chip->chg_vbatdet_lo.irq,
qpnp_chg_vbatdet_lo_irq_handler,
IRQF_TRIGGER_RISING,
"vbat-det-lo", chip);
if (rc < 0) {
pr_err("Can't request %d vbat-det-lo: %d\n",
- chip->chg_vbatdet_lo_irq, rc);
+ chip->chg_vbatdet_lo.irq, rc);
return rc;
}
- enable_irq_wake(chip->chg_fastchg_irq);
- enable_irq_wake(chip->chg_trklchg_irq);
- enable_irq_wake(chip->chg_failed_irq);
- disable_irq_nosync(chip->chg_vbatdet_lo_irq);
- enable_irq_wake(chip->chg_vbatdet_lo_irq);
+ enable_irq_wake(chip->chg_trklchg.irq);
+ enable_irq_wake(chip->chg_failed.irq);
+ qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
+ enable_irq_wake(chip->chg_vbatdet_lo.irq);
break;
case SMBB_BAT_IF_SUBTYPE:
case SMBBP_BAT_IF_SUBTYPE:
case SMBCL_BAT_IF_SUBTYPE:
- chip->batt_pres_irq = spmi_get_irq_byname(spmi,
+ chip->batt_pres.irq = spmi_get_irq_byname(spmi,
spmi_resource, "batt-pres");
- if (chip->batt_pres_irq < 0) {
+ if (chip->batt_pres.irq < 0) {
pr_err("Unable to get batt-pres irq\n");
return rc;
}
- rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
+ rc = devm_request_irq(chip->dev, chip->batt_pres.irq,
qpnp_chg_bat_if_batt_pres_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"batt-pres", chip);
if (rc < 0) {
pr_err("Can't request %d batt-pres irq: %d\n",
- chip->batt_pres_irq, rc);
+ chip->batt_pres.irq, rc);
return rc;
}
- enable_irq_wake(chip->batt_pres_irq);
+ enable_irq_wake(chip->batt_pres.irq);
break;
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
case SMBCL_USB_CHGPTH_SUBTYPE:
- chip->usbin_valid_irq = spmi_get_irq_byname(spmi,
+ chip->usbin_valid.irq = spmi_get_irq_byname(spmi,
spmi_resource, "usbin-valid");
- if (chip->usbin_valid_irq < 0) {
+ if (chip->usbin_valid.irq < 0) {
pr_err("Unable to get usbin irq\n");
return rc;
}
- rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
+ rc = devm_request_irq(chip->dev, chip->usbin_valid.irq,
qpnp_chg_usb_usbin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"usbin-valid", chip);
if (rc < 0) {
pr_err("Can't request %d usbin-valid: %d\n",
- chip->usbin_valid_irq, rc);
+ chip->usbin_valid.irq, rc);
return rc;
}
- chip->chg_gone_irq = spmi_get_irq_byname(spmi,
+ chip->chg_gone.irq = spmi_get_irq_byname(spmi,
spmi_resource, "chg-gone");
- if (chip->chg_gone_irq < 0) {
+ if (chip->chg_gone.irq < 0) {
pr_err("Unable to get chg-gone irq\n");
return rc;
}
- rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
+ rc = devm_request_irq(chip->dev, chip->chg_gone.irq,
qpnp_chg_usb_chg_gone_irq_handler,
IRQF_TRIGGER_RISING,
"chg-gone", chip);
if (rc < 0) {
pr_err("Can't request %d chg-gone: %d\n",
- chip->chg_gone_irq, rc);
+ chip->chg_gone.irq, rc);
return rc;
}
- enable_irq_wake(chip->usbin_valid_irq);
- enable_irq_wake(chip->chg_gone_irq);
+
+ enable_irq_wake(chip->usbin_valid.irq);
+ enable_irq_wake(chip->chg_gone.irq);
break;
case SMBB_DC_CHGPTH_SUBTYPE:
- chip->dcin_valid_irq = spmi_get_irq_byname(spmi,
+ chip->dcin_valid.irq = spmi_get_irq_byname(spmi,
spmi_resource, "dcin-valid");
- if (chip->dcin_valid_irq < 0) {
+ if (chip->dcin_valid.irq < 0) {
pr_err("Unable to get dcin irq\n");
return -rc;
}
- rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
+ rc = devm_request_irq(chip->dev, chip->dcin_valid.irq,
qpnp_chg_dc_dcin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"dcin-valid", chip);
if (rc < 0) {
pr_err("Can't request %d dcin-valid: %d\n",
- chip->dcin_valid_irq, rc);
+ chip->dcin_valid.irq, rc);
return rc;
}
- enable_irq_wake(chip->dcin_valid_irq);
+ enable_irq_wake(chip->dcin_valid.irq);
break;
}
}
@@ -1853,7 +2218,9 @@
struct spmi_resource *spmi_resource)
{
int rc = 0;
- u8 reg;
+ u8 reg = 0;
+ struct regulator_init_data *init_data;
+ struct regulator_desc *rdesc;
switch (subtype) {
case SMBB_CHGR_SUBTYPE:
@@ -1932,6 +2299,20 @@
case SMBB_BAT_IF_SUBTYPE:
case SMBBP_BAT_IF_SUBTYPE:
case SMBCL_BAT_IF_SUBTYPE:
+ /* Select battery presence detection */
+ if (chip->bpd_detection == 1)
+ reg = BAT_ID_EN;
+ else if (chip->bpd_detection == 2)
+ reg = BAT_ID_EN | BAT_THM_EN;
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + BAT_IF_BPD_CTRL,
+ BAT_IF_BPD_CTRL_SEL,
+ reg, 1);
+ if (rc) {
+ pr_debug("failed to chose BPD rc=%d\n", rc);
+ return rc;
+ }
/* Force on VREF_BAT_THM */
rc = qpnp_chg_masked_write(chip,
chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
@@ -1956,6 +2337,38 @@
}
}
+ init_data = of_get_regulator_init_data(chip->dev,
+ spmi_resource->of_node);
+ if (!init_data) {
+ pr_err("unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ if (init_data->constraints.name) {
+ if (of_get_property(chip->dev->of_node,
+ "otg-parent-supply", NULL))
+ init_data->supply_regulator = "otg-parent";
+
+ rdesc = &(chip->otg_vreg.rdesc);
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->ops = &qpnp_chg_otg_reg_ops;
+ rdesc->name = init_data->constraints.name;
+
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_STATUS;
+
+ chip->otg_vreg.rdev = regulator_register(rdesc,
+ chip->dev, init_data, chip,
+ spmi_resource->of_node);
+ if (IS_ERR(chip->otg_vreg.rdev)) {
+ rc = PTR_ERR(chip->otg_vreg.rdev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("OTG reg failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
rc = qpnp_chg_masked_write(chip,
chip->usb_chgpth_base + USB_OVP_CTL,
USB_VALID_DEB_20MS,
@@ -1981,6 +2394,38 @@
break;
case SMBB_BOOST_SUBTYPE:
case SMBBP_BOOST_SUBTYPE:
+ init_data = of_get_regulator_init_data(chip->dev,
+ spmi_resource->of_node);
+ if (!init_data) {
+ pr_err("unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ if (init_data->constraints.name) {
+ if (of_get_property(chip->dev->of_node,
+ "boost-parent-supply", NULL))
+ init_data->supply_regulator = "boost-parent";
+
+ rdesc = &(chip->boost_vreg.rdesc);
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->ops = &qpnp_chg_boost_reg_ops;
+ rdesc->name = init_data->constraints.name;
+
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_STATUS
+ | REGULATOR_CHANGE_VOLTAGE;
+
+ chip->boost_vreg.rdev = regulator_register(rdesc,
+ chip->dev, init_data, chip,
+ spmi_resource->of_node);
+ if (IS_ERR(chip->boost_vreg.rdev)) {
+ rc = PTR_ERR(chip->boost_vreg.rdev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("boost reg failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
break;
case SMBB_MISC_SUBTYPE:
case SMBBP_MISC_SUBTYPE:
@@ -2031,6 +2476,7 @@
qpnp_charger_read_dt_props(struct qpnp_chg_chip *chip)
{
int rc = 0;
+ const char *bpd;
OF_PROP_READ(chip, max_voltage_mv, "vddmax-mv", rc, 0);
OF_PROP_READ(chip, min_voltage_mv, "vinmin-mv", rc, 0);
@@ -2050,6 +2496,18 @@
if (rc)
return rc;
+ rc = of_property_read_string(chip->spmi->dev.of_node,
+ "qcom,bpd-detection", &bpd);
+ if (rc) {
+ pr_debug("no bpd-detection specified, ignored\n");
+ } else {
+ chip->bpd_detection = get_bpd(bpd);
+ if (chip->bpd_detection < 0) {
+ pr_err("failed to determine bpd schema %d\n", rc);
+ return rc;
+ }
+ }
+
/* Look up JEITA compliance parameters if cool and warm temp provided */
if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
rc = qpnp_adc_tm_is_ready();
@@ -2070,6 +2528,18 @@
chip->charging_disabled = of_property_read_bool(chip->spmi->dev.of_node,
"qcom,charging-disabled");
+ /* Get the duty-cycle-100p property */
+ chip->duty_cycle_100p = of_property_read_bool(
+ chip->spmi->dev.of_node,
+ "qcom,duty-cycle-100p");
+ if (chip->duty_cycle_100p) {
+ rc = qpnp_buck_set_100_duty_cycle_enable(chip, 1);
+ if (rc) {
+ pr_err("failed to enable duty cycle %d\n", rc);
+ return rc;
+ }
+ }
+
/* Get the fake-batt-values property */
chip->use_default_batt_values =
of_property_read_bool(chip->spmi->dev.of_node,
@@ -2219,7 +2689,8 @@
chip->usb_chgpth_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
- pr_err("Failed to init subtype 0x%x rc=%d\n",
+ if (rc != -EPROBE_DEFER)
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
subtype, rc);
goto fail_chg_enable;
}
@@ -2238,7 +2709,8 @@
chip->boost_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
- pr_err("Failed to init subtype 0x%x rc=%d\n",
+ if (rc != -EPROBE_DEFER)
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
subtype, rc);
goto fail_chg_enable;
}
@@ -2361,8 +2833,9 @@
if (qpnp_chg_is_usb_chg_plugged_in(chip))
power_supply_set_online(chip->usb_psy, 1);
- pr_info("success chg_dis = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
+ pr_info("success chg_dis = %d, bpd = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
chip->charging_disabled,
+ chip->bpd_detection,
qpnp_chg_is_usb_chg_plugged_in(chip),
qpnp_chg_is_dc_chg_plugged_in(chip),
get_prop_batt_present(chip),
@@ -2390,6 +2863,12 @@
cancel_work_sync(&chip->adc_measure_work);
cancel_delayed_work_sync(&chip->eoc_work);
+ if (chip->otg_vreg.rdev)
+ regulator_unregister(chip->otg_vreg.rdev);
+
+ if (chip->boost_vreg.rdev)
+ regulator_unregister(chip->boost_vreg.rdev);
+
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c8fdc6b..5f21c7a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -603,16 +603,11 @@
case UTP_CMD_TYPE_SCSI:
case UTP_CMD_TYPE_DEV_MANAGE:
ufshcd_prepare_req_desc(lrbp, &upiu_flags);
- if (lrbp->cmd && lrbp->command_type == UTP_CMD_TYPE_SCSI)
+ if (lrbp->command_type == UTP_CMD_TYPE_SCSI)
ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
- else if (lrbp->cmd)
+ else
ufshcd_prepare_utp_query_req_upiu(hba, lrbp,
upiu_flags);
- else {
- dev_err(hba->dev, "%s: Invalid UPIU request\n",
- __func__);
- ret = -EINVAL;
- }
break;
case UTP_CMD_TYPE_UFS:
/* For UFS native command implementation */
@@ -725,8 +720,7 @@
bool sdev_lookup = true;
if (!hba || !query || !response) {
- dev_err(hba->dev,
- "%s: NULL pointer hba = %p, query = %p response = %p\n",
+ pr_err("%s: NULL pointer hba = %p, query = %p response = %p\n",
__func__, hba, query, response);
return -EINVAL;
}
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index f01a078..52608af 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/interrupt.h>
+#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/io.h>
@@ -258,6 +259,7 @@
struct tsens_tm_device {
struct platform_device *pdev;
+ struct workqueue_struct *tsens_wq;
bool prev_reading_avail;
bool calibration_less_mode;
bool tsens_local_init;
@@ -655,7 +657,7 @@
}
if (upper_thr || lower_thr) {
/* Notify user space */
- schedule_work(&tm->sensor[i].work);
+ queue_work(tm->tsens_wq, &tm->sensor[i].work);
rc = tsens_get_sw_id_mapping(
tm->sensor[i].sensor_hw_num,
&sensor_sw_id);
@@ -673,7 +675,7 @@
static irqreturn_t tsens_isr(int irq, void *data)
{
- schedule_work(&tmdev->tsens_work);
+ queue_work(tmdev->tsens_wq, &tmdev->tsens_work);
return IRQ_HANDLED;
}
@@ -1506,6 +1508,12 @@
return -ENODEV;
tmdev->pdev = pdev;
+ tmdev->tsens_wq = alloc_workqueue("tsens_wq", WQ_HIGHPRI, 0);
+ if (!tmdev->tsens_wq) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+
rc = tsens_calib_sensors();
if (rc < 0) {
pr_err("Calibration failed\n");
@@ -1520,6 +1528,8 @@
return 0;
fail:
+ if (tmdev->tsens_wq)
+ destroy_workqueue(tmdev->tsens_wq);
if (tmdev->tsens_calib_addr)
iounmap(tmdev->tsens_calib_addr);
if (tmdev->res_calib_mem)
@@ -1610,6 +1620,7 @@
release_mem_region(tmdev->res_tsens_mem->start,
tmdev->tsens_len);
free_irq(tmdev->tsens_irq, tmdev);
+ destroy_workqueue(tmdev->tsens_wq);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 814817b..ab59864 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -596,7 +596,14 @@
pr_info("%s: Max frequency reset for cpu%d\n",
KBUILD_MODNAME, cpu);
- ret = cpufreq_update_policy(cpu);
+ if (cpu_online(cpu)) {
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (!policy)
+ return ret;
+ ret = cpufreq_driver_target(policy, policy->cur,
+ CPUFREQ_RELATION_H);
+ cpufreq_cpu_put(policy);
+ }
return ret;
}
@@ -748,14 +755,56 @@
return ret;
}
+static void __cpuinit do_freq_control(long temp)
+{
+ int ret = 0;
+ int cpu = 0;
+ uint32_t max_freq = limited_max_freq;
+
+ if (temp >= msm_thermal_info.limit_temp_degC) {
+ if (limit_idx == limit_idx_low)
+ return;
+
+ limit_idx -= msm_thermal_info.freq_step;
+ if (limit_idx < limit_idx_low)
+ limit_idx = limit_idx_low;
+ max_freq = table[limit_idx].frequency;
+ } else if (temp < msm_thermal_info.limit_temp_degC -
+ msm_thermal_info.temp_hysteresis_degC) {
+ if (limit_idx == limit_idx_high)
+ return;
+
+ limit_idx += msm_thermal_info.freq_step;
+ if (limit_idx >= limit_idx_high) {
+ limit_idx = limit_idx_high;
+ max_freq = MSM_CPUFREQ_NO_LIMIT;
+ } else
+ max_freq = table[limit_idx].frequency;
+ }
+
+ if (max_freq == limited_max_freq)
+ return;
+
+ /* Update new limits */
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
+ continue;
+ ret = update_cpu_max_freq(cpu, max_freq);
+ if (ret)
+ pr_debug(
+ "%s: Unable to limit cpu%d max freq to %d\n",
+ KBUILD_MODNAME, cpu, max_freq);
+ }
+
+}
+
static void __cpuinit check_temp(struct work_struct *work)
{
static int limit_init;
struct tsens_device tsens_dev;
long temp = 0;
- uint32_t max_freq = limited_max_freq;
- int cpu = 0;
int ret = 0;
+
tsens_dev.sensor_num = msm_thermal_info.sensor_id;
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
@@ -775,38 +824,7 @@
do_core_control(temp);
do_vdd_restriction();
do_psm();
-
- if (temp >= msm_thermal_info.limit_temp_degC) {
- if (limit_idx == limit_idx_low)
- goto reschedule;
-
- limit_idx -= msm_thermal_info.freq_step;
- if (limit_idx < limit_idx_low)
- limit_idx = limit_idx_low;
- max_freq = table[limit_idx].frequency;
- } else if (temp < msm_thermal_info.limit_temp_degC -
- msm_thermal_info.temp_hysteresis_degC) {
- if (limit_idx == limit_idx_high)
- goto reschedule;
-
- limit_idx += msm_thermal_info.freq_step;
- if (limit_idx >= limit_idx_high) {
- limit_idx = limit_idx_high;
- max_freq = MSM_CPUFREQ_NO_LIMIT;
- } else
- max_freq = table[limit_idx].frequency;
- }
- if (max_freq == limited_max_freq)
- goto reschedule;
-
- /* Update new limits */
- for_each_possible_cpu(cpu) {
- ret = update_cpu_max_freq(cpu, max_freq);
- if (ret)
- pr_debug(
- "%s: Unable to limit cpu%d max freq to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
- }
+ do_freq_control(temp);
reschedule:
if (enabled)
@@ -1599,6 +1617,9 @@
if (ret)
goto fail;
+ key = "qcom,freq-control-mask";
+ ret = of_property_read_u32(node, key, &data.freq_control_mask);
+
key = "qcom,core-limit-temp";
ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 8760603..d1545dc 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1,6 +1,6 @@
/* drivers/tty/n_smux.c
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -259,6 +259,8 @@
unsigned powerdown_enabled;
unsigned power_ctl_remote_req_received;
struct list_head power_queue;
+ unsigned remote_initiated_wakeup_count;
+ unsigned local_initiated_wakeup_count;
};
@@ -279,6 +281,7 @@
[SMUX_CMD_CLOSE_LCH] = "CLOSE",
[SMUX_CMD_STATUS] = "STATUS",
[SMUX_CMD_PWR_CTL] = "PWR",
+ [SMUX_CMD_DELAY] = "DELAY",
[SMUX_CMD_BYTE] = "Raw Byte",
};
@@ -1908,6 +1911,7 @@
/* wakeup system */
SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
+ smux.remote_initiated_wakeup_count++;
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_wakeup_work);
queue_work(smux_tx_wq, &smux_tx_work);
@@ -2163,6 +2167,62 @@
}
/**
+ * Sends a delay command to the remote side.
+ *
+ * @ms: Time in milliseconds for the remote side to delay
+ *
+ * This command defines the delay that the remote side will use
+ * to slow the response time for DATA commands.
+ */
+void smux_set_loopback_data_reply_delay(uint32_t ms)
+{
+ struct smux_lch_t *ch = &smux_lch[SMUX_TEST_LCID];
+ struct smux_pkt_t *pkt;
+
+ pkt = smux_alloc_pkt();
+ if (!pkt) {
+ pr_err("%s: unable to allocate packet\n", __func__);
+ return;
+ }
+
+ pkt->hdr.lcid = ch->lcid;
+ pkt->hdr.cmd = SMUX_CMD_DELAY;
+ pkt->hdr.flags = 0;
+ pkt->hdr.payload_len = sizeof(uint32_t);
+ pkt->hdr.pad_len = 0;
+
+ if (smux_alloc_pkt_payload(pkt)) {
+ pr_err("%s: unable to allocate payload\n", __func__);
+ smux_free_pkt(pkt);
+ return;
+ }
+ memcpy(pkt->payload, &ms, sizeof(uint32_t));
+
+ smux_tx_queue(pkt, ch, 1);
+}
+
+/**
+ * Retrieve wakeup counts.
+ *
+ * @local_cnt: Pointer to local wakeup count
+ * @remote_cnt: Pointer to remote wakeup count
+ */
+void smux_get_wakeup_counts(int *local_cnt, int *remote_cnt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+
+ if (local_cnt)
+ *local_cnt = smux.local_initiated_wakeup_count;
+
+ if (remote_cnt)
+ *remote_cnt = smux.remote_initiated_wakeup_count;
+
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+}
+
+/**
* Add channel to transmit-ready list and trigger transmit worker.
*
* @ch Channel to add
@@ -2744,6 +2804,7 @@
SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_ON);
+ smux.local_initiated_wakeup_count++;
smux.power_state = SMUX_PWR_TURNING_ON;
spin_unlock_irqrestore(&smux.tx_lock_lha2,
flags);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 8fdec86..b9a2e89 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -1,6 +1,6 @@
/* drivers/tty/smux_private.h
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -122,6 +122,7 @@
SMUX_CMD_CLOSE_LCH = 0x2,
SMUX_CMD_STATUS = 0x3,
SMUX_CMD_PWR_CTL = 0x4,
+ SMUX_CMD_DELAY = 0x5,
SMUX_CMD_BYTE, /* for internal usage */
SMUX_NUM_COMMANDS
@@ -181,6 +182,8 @@
void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
bool smux_remote_is_active(void);
+void smux_set_loopback_data_reply_delay(uint32_t ms);
+void smux_get_wakeup_counts(int *local_cnt, int *remote_cnt);
/* testing parameters */
extern int smux_byte_loopback;
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index e1d9975..8d17674 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -1,6 +1,6 @@
/* drivers/tty/smux_test.c
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -20,11 +20,17 @@
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/termios.h>
+#include <linux/sched.h>
#include <linux/smux.h>
#include <mach/subsystem_restart.h>
#include "smux_private.h"
#define DEBUG_BUFMAX 4096
+#define RED_ZONE_SIZE 16
+#define RED_ZONE_PRE_CH 0xAB
+#define RED_ZONE_POS_CH 0xBA
+#define SMUX_REMOTE_INACTIVITY_TIME_MS 50
+#define SMUX_REMOTE_DELAY_TIME_MS 250
/**
* Unit test assertion for logging test cases.
@@ -138,7 +144,7 @@
/**
* Allocates a new buffer for SMUX for every call.
*/
-int get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+static int get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
{
void *rx_buf;
@@ -216,7 +222,7 @@
*
* @cb Mock callback data
*/
-void mock_cb_data_init(struct smux_mock_callback *cb)
+static void mock_cb_data_init(struct smux_mock_callback *cb)
{
init_completion(&cb->cb_completion);
spin_lock_init(&cb->lock);
@@ -232,7 +238,7 @@
*
* All packets are freed and counters reset to zero.
*/
-void mock_cb_data_reset(struct smux_mock_callback *cb)
+static void mock_cb_data_reset(struct smux_mock_callback *cb)
{
cb->cb_count = 0;
INIT_COMPLETION(cb->cb_completion);
@@ -341,7 +347,7 @@
* Mock object event callback. Used to logs events for analysis in the unit
* tests.
*/
-void smux_mock_cb(void *priv, int event, const void *metadata)
+static void smux_mock_cb(void *priv, int event, const void *metadata)
{
struct smux_mock_callback *cb_data_ptr;
struct mock_write_event *write_event_meta;
@@ -518,12 +524,17 @@
for (; vectors->data != NULL; ++vectors) {
const char *test_data = vectors->data;
const unsigned test_len = vectors->len;
+ unsigned long long start_t;
+ unsigned long long end_t;
+ unsigned long long val;
+ unsigned long rem;
i += scnprintf(buf + i, max - i,
- "Writing vector %p len %d\n",
+ "Writing vector %p len %d: ",
test_data, test_len);
/* write data */
+ start_t = sched_clock();
msm_smux_write(SMUX_TEST_LCID, (void *)0xCAFEFACE,
test_data, test_len);
UT_ASSERT_INT(ret, ==, 0);
@@ -538,6 +549,7 @@
(int)wait_for_completion_timeout(
&cb_data.cb_completion, HZ),
>, 0);
+ end_t = sched_clock();
UT_ASSERT_INT(cb_data.cb_count, >=, 1);
UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
@@ -569,16 +581,28 @@
hex_dump_to_buffer(test_data, test_len,
16, 1, linebuff, sizeof(linebuff), 1);
i += scnprintf(buf + i, max - i,
- "Expected:\n%s\n\n", linebuff);
+ "Failed\nExpected:\n%s\n\n", linebuff);
hex_dump_to_buffer(read_event->meta.buffer,
read_event->meta.len,
16, 1, linebuff, sizeof(linebuff), 1);
i += scnprintf(buf + i, max - i,
- "Actual:\n%s\n", linebuff);
+ "Failed\nActual:\n%s\n", linebuff);
failed = 1;
break;
}
+
+ /* calculate throughput stats */
+ val = end_t - start_t;
+ rem = do_div(val, 1000);
+ i += scnprintf(buf + i, max - i,
+ "OK - %u us",
+ (unsigned int)val);
+
+ val = 1000000000LL * 2 * test_len;
+ rem = do_div(val, end_t - start_t);
+ i += scnprintf(buf + i, max - i,
+ " (%u kB/sec)\n", (unsigned int)val);
mock_cb_data_reset(&cb_data);
}
@@ -682,7 +706,7 @@
* Run a basic loopback test followed by a subsystem restart and then another
* loopback test.
*/
-static int smux_ut_remote_ssr_basic(char *buf, int max)
+static int smux_ut_ssr_remote_basic(char *buf, int max)
{
const struct test_vector test_data[] = {
{"hello\0world\n", sizeof("hello\0world\n")},
@@ -723,7 +747,7 @@
/**
* Verify Subsystem Restart Support During Port Open
*/
-static int smux_ut_remote_ssr_open(char *buf, int max)
+static int smux_ut_ssr_remote_open(char *buf, int max)
{
static struct smux_mock_callback cb_data;
static int cb_initialized;
@@ -805,7 +829,7 @@
*
* @returns Number of bytes written to @buf
*/
-static int smux_ut_remote_ssr_rx_buff_retry(char *buf, int max)
+static int smux_ut_ssr_remote_rx_buff_retry(char *buf, int max)
{
static struct smux_mock_callback cb_data;
static int cb_initialized;
@@ -897,9 +921,10 @@
mock_cb_data_reset(&cb_data);
return i;
}
+
/**
* Fill test pattern into provided buffer including an optional
- * redzone 16 bytes before and 16 bytes after the buffer.
+ * redzone before and after the buffer.
*
* buf ---------
* redzone
@@ -909,70 +934,75 @@
* redzone
* ---------
*
- * @buf Pointer to the buffer of size len or len+32 (redzone)
- * @len Length of the *data* buffer (excluding 32-byte redzone)
+ * @buf Pointer to the buffer of size len or len+2*RED_ZONE_SIZE (redzone)
+ * @len Length of the *data* buffer (excluding the extra redzone buffers)
* @redzone If true, adds redzone data
*
- * @returns pointer to buffer (buf + 16 if redzone enabled)
+ * @returns pointer to buffer (buf + RED_ZONE_SIZE if redzone enabled)
*/
-uint8_t *test_pattern_fill(char *buf, int len, int redzone)
+static uint8_t *test_pattern_fill(char *buf, int len, int redzone)
{
- void *ret;
+ char *buf_ptr;
uint8_t ch;
- ret = buf;
if (redzone) {
- memset((char *)buf, 0xAB, 16);
- memset((char *)buf + len, 0xBA, 16);
- ret += 16;
+ memset(buf, RED_ZONE_PRE_CH, RED_ZONE_SIZE);
+ buf += RED_ZONE_SIZE;
+ memset(buf + len, RED_ZONE_POS_CH, RED_ZONE_SIZE);
}
- /* fill with test pattern */
- for (ch = 0; len > 0; --len, ++ch)
- *buf++ = (char)ch;
+ for (ch = 0, buf_ptr = buf; len > 0; --len, ++ch)
+ *buf_ptr++ = (char)ch;
- return ret;
+ return buf;
}
/**
* Verify test pattern generated by test_pattern_fill.
*
* @buf_ptr Pointer to buffer pointer
- * @len Length of the *data* buffer (excluding 32-byte redzone)
+ * @len Length of the *data* buffer (excluding redzone bytes)
* @redzone If true, verifies redzone and adjusts *buf_ptr
* @errmsg Buffer for error message
* @errmsg_max Size of error message buffer
*
* @returns 0 for success; length of error message otherwise
*/
-unsigned test_pattern_verify(char **buf_ptr, int len, int redzone,
+static unsigned test_pattern_verify(char **buf_ptr, int len, int redzone,
char *errmsg, int errmsg_max)
{
int n;
int i = 0;
char linebuff[80];
+ char *zone_ptr;
if (redzone) {
- *buf_ptr -= 16;
+ *buf_ptr -= RED_ZONE_SIZE;
+ zone_ptr = *buf_ptr;
/* verify prefix redzone */
- for (n = 0; n < 16; ++n) {
- if (*buf_ptr[n] != 0xAB) {
- hex_dump_to_buffer(*buf_ptr, 16,
- 16, 1, linebuff, sizeof(linebuff), 1);
+ for (n = 0; n < RED_ZONE_SIZE; ++n) {
+ if (zone_ptr[n] != RED_ZONE_PRE_CH) {
+ hex_dump_to_buffer(zone_ptr, RED_ZONE_SIZE,
+ RED_ZONE_SIZE, 1, linebuff,
+ sizeof(linebuff), 1);
i += scnprintf(errmsg + i, errmsg_max - i,
- "Redzone violation: %s\n", linebuff);
+ "Pre-redzone violation: %s\n",
+ linebuff);
break;
}
}
/* verify postfix redzone */
- for (n = 0; n < 16; ++n) {
- if (*buf_ptr[len + n] != 0xBA) {
- hex_dump_to_buffer(&(*buf_ptr)[len], 16,
- 16, 1, linebuff, sizeof(linebuff), 1);
+ zone_ptr = *buf_ptr + RED_ZONE_SIZE + len;
+ for (n = 0; n < RED_ZONE_SIZE; ++n) {
+ if (zone_ptr[n] != RED_ZONE_POS_CH) {
+ hex_dump_to_buffer(zone_ptr, RED_ZONE_SIZE,
+ RED_ZONE_SIZE, 1, linebuff,
+ sizeof(linebuff), 1);
i += scnprintf(errmsg + i, errmsg_max - i,
- "Redzone violation: %s\n", linebuff);
+ "Post-redzone violation: %s\n",
+ linebuff);
break;
}
}
@@ -1001,6 +1031,7 @@
{0, 256},
{0, 512},
{0, 1024},
+ {0, 1500},
{0, 2048},
{0, 4096},
{0, 0},
@@ -1011,9 +1042,7 @@
/* generate test data */
for (tv = test_data; tv->len > 0; ++tv) {
- tv->data = kmalloc(tv->len + 32, GFP_KERNEL);
- pr_err("%s: allocating %p len %d\n",
- __func__, tv->data, tv->len);
+ tv->data = kmalloc(tv->len + 2 * RED_ZONE_SIZE, GFP_KERNEL);
if (!tv->data) {
i += scnprintf(buf + i, max - i,
"%s: Unable to allocate %d bytes\n",
@@ -1021,7 +1050,7 @@
failed = 1;
goto out;
}
- test_pattern_fill((uint8_t *)tv->data, tv->len, 1);
+ tv->data = test_pattern_fill((uint8_t *)tv->data, tv->len, 1);
}
/* run test */
@@ -1038,11 +1067,9 @@
}
for (tv = test_data; tv->len > 0; ++tv) {
- if (!tv->data) {
+ if (tv->data) {
i += test_pattern_verify((char **)&tv->data,
tv->len, 1, buf + i, max - i);
- pr_err("%s: freeing %p len %d\n", __func__,
- tv->data, tv->len);
kfree(tv->data);
}
}
@@ -1112,6 +1139,59 @@
}
/**
+ * Run a large packet test for throughput metrics.
+ *
+ * Repeatedly send a packet for 100 iterations to get throughput metrics.
+ */
+static int smux_ut_remote_throughput(char *buf, int max)
+{
+ struct test_vector test_data[] = {
+ {0, 1500},
+ {0, 0},
+ };
+ int failed = 0;
+ int i = 0;
+ int loop = 0;
+ struct test_vector *tv;
+ int ret;
+
+ /* generate test data */
+ for (tv = test_data; tv->len > 0; ++tv) {
+ tv->data = kmalloc(tv->len, GFP_KERNEL);
+ if (!tv->data) {
+ i += scnprintf(buf + i, max - i,
+ "%s: Unable to allocate %d bytes\n",
+ __func__, tv->len);
+ failed = 1;
+ goto out;
+ }
+ test_pattern_fill((uint8_t *)tv->data, tv->len, 0);
+ }
+
+ /* run test */
+ i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+ while (!failed && loop < 100) {
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
+ ++loop;
+ }
+
+out:
+ if (failed) {
+ pr_err("%s: Failed\n", __func__);
+ i += scnprintf(buf + i, max - i, "\tFailed\n");
+ }
+
+ for (tv = test_data; tv->len > 0; ++tv)
+ kfree(tv->data);
+
+ return i;
+}
+
+/**
* Verify set and get operations for each TIOCM bit.
*
* @buf Buffer for status message
@@ -2083,6 +2163,126 @@
return i;
}
+/**
+ * Verify Remote-initiated wakeup test case.
+ *
+ * @buf Output buffer for failure/status messages
+ * @max Size of @buf
+ */
+static int smux_ut_remote_initiated_wakeup(char *buf, int max)
+{
+ int i = 0;
+ int failed = 0;
+ static struct smux_mock_callback cb_data;
+ static int cb_initialized;
+ int ret;
+
+ if (!cb_initialized)
+ mock_cb_data_init(&cb_data);
+
+ smux_set_loopback_data_reply_delay(SMUX_REMOTE_DELAY_TIME_MS);
+ mock_cb_data_reset(&cb_data);
+ do {
+ unsigned long start_j;
+ unsigned transfer_time;
+ unsigned lwakeups_start;
+ unsigned rwakeups_start;
+ unsigned lwakeups_end;
+ unsigned rwakeups_end;
+ unsigned lwakeup_delta;
+ unsigned rwakeup_delta;
+
+ /* open port */
+ ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+ get_rx_buffer);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ), >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* do local wakeup test and send echo packet */
+ msleep(SMUX_REMOTE_INACTIVITY_TIME_MS);
+ smux_get_wakeup_counts(&lwakeups_start, &rwakeups_start);
+ msm_smux_write(SMUX_TEST_LCID, (void *)0x12345678,
+ "Hello", 5);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ), >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* verify local initiated wakeup */
+ smux_get_wakeup_counts(&lwakeups_end, &rwakeups_end);
+ if (lwakeups_end > lwakeups_start)
+ i += scnprintf(buf + i, max - i,
+ "\tGood - have Apps-initiated wakeup\n");
+ else
+ i += scnprintf(buf + i, max - i,
+ "\tBad - no Apps-initiated wakeup\n");
+
+ /* verify remote wakeup and echo response */
+ smux_get_wakeup_counts(&lwakeups_start, &rwakeups_start);
+ start_j = jiffies;
+ INIT_COMPLETION(cb_data.cb_completion);
+ if (!cb_data.event_read_done)
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion,
+ SMUX_REMOTE_DELAY_TIME_MS * 2),
+ >, 0);
+ transfer_time = (unsigned)jiffies_to_msecs(jiffies - start_j);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ UT_ASSERT_INT_IN_RANGE(transfer_time,
+ SMUX_REMOTE_DELAY_TIME_MS -
+ SMUX_REMOTE_INACTIVITY_TIME_MS,
+ SMUX_REMOTE_DELAY_TIME_MS +
+ SMUX_REMOTE_INACTIVITY_TIME_MS);
+ smux_get_wakeup_counts(&lwakeups_end, &rwakeups_end);
+
+ lwakeup_delta = lwakeups_end - lwakeups_end;
+ rwakeup_delta = rwakeups_end - rwakeups_end;
+ if (rwakeup_delta && lwakeup_delta) {
+ i += scnprintf(buf + i, max - i,
+ "\tBoth local and remote wakeup - re-run test (transfer time %d ms)\n",
+ transfer_time);
+ failed = 1;
+ break;
+ } else if (lwakeup_delta) {
+ i += scnprintf(buf + i, max - i,
+ "\tLocal wakeup only (transfer time %d ms) - FAIL\n",
+ transfer_time);
+ failed = 1;
+ break;
+ } else {
+ i += scnprintf(buf + i, max - i,
+ "\tRemote wakeup verified (transfer time %d ms) - OK\n",
+ transfer_time);
+ }
+ } while (0);
+
+ if (!failed) {
+ i += scnprintf(buf + i, max - i, "\tOK\n");
+ } else {
+ pr_err("%s: Failed\n", __func__);
+ i += scnprintf(buf + i, max - i, "\tFailed\n");
+ i += mock_cb_data_print(&cb_data, buf + i, max - i);
+ }
+
+ mock_cb_data_reset(&cb_data);
+ msm_smux_close(SMUX_TEST_LCID);
+ wait_for_completion_timeout(&cb_data.cb_completion, HZ);
+
+ mock_cb_data_reset(&cb_data);
+ smux_set_loopback_data_reply_delay(0);
+
+ return i;
+}
+
static char debug_buffer[DEBUG_BUFMAX];
static ssize_t debug_read(struct file *file, char __user *buf,
@@ -2148,15 +2348,18 @@
smux_ut_local_get_rx_buff_retry);
debug_create("ut_local_get_rx_buff_retry_auto", 0444, dent,
smux_ut_local_get_rx_buff_retry_auto);
- debug_create("ut_remote_ssr_basic", 0444, dent,
- smux_ut_remote_ssr_basic);
- debug_create("ut_remote_ssr_open", 0444, dent,
- smux_ut_remote_ssr_open);
- debug_create("ut_remote_ssr_rx_buff_retry", 0444, dent,
- smux_ut_remote_ssr_rx_buff_retry);
+ debug_create("ut_ssr_remote_basic", 0444, dent,
+ smux_ut_ssr_remote_basic);
+ debug_create("ut_ssr_remote_open", 0444, dent,
+ smux_ut_ssr_remote_open);
+ debug_create("ut_ssr_remote_rx_buff_retry", 0444, dent,
+ smux_ut_ssr_remote_rx_buff_retry);
debug_create("ut_remote_tx_stop", 0444, dent,
smux_ut_remote_tx_stop);
-
+ debug_create("ut_remote_throughput", 0444, dent,
+ smux_ut_remote_throughput);
+ debug_create("ut_remote_initiated_wakeup", 0444, dent,
+ smux_ut_remote_initiated_wakeup);
return 0;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index c08a259..1059a4d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1706,6 +1706,7 @@
int ret = 0;
u32 reg;
+ pm_runtime_get_sync(dwc->dev);
spin_lock_irqsave(&dwc->lock, flags);
if (dwc->gadget_driver) {
@@ -1765,6 +1766,7 @@
dwc3_ep0_out_start(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
+ pm_runtime_put(dwc->dev);
return 0;
@@ -1773,6 +1775,7 @@
err0:
spin_unlock_irqrestore(&dwc->lock, flags);
+ pm_runtime_put(dwc->dev);
return ret;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 38f08fc..af82656 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -79,7 +79,7 @@
*****************************************************************************/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#define USB_MAX_TIMEOUT 100 /* 100msec timeout */
+#define USB_MAX_TIMEOUT 25 /* 25msec timeout */
#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
@@ -2275,8 +2275,11 @@
gadget->otg_srp_reqd = 0;
udc->driver->disconnect(gadget);
+
+ spin_lock_irqsave(udc->lock, flags);
_ep_nuke(&udc->ep0out);
_ep_nuke(&udc->ep0in);
+ spin_unlock_irqrestore(udc->lock, flags);
if (udc->ep0in.last_zptr) {
dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
@@ -2325,7 +2328,7 @@
/*stop charging upon reset */
if (udc->transceiver)
- usb_phy_set_power(udc->transceiver, 0);
+ usb_phy_set_power(udc->transceiver, 100);
retval = _gadget_stop_activity(&udc->gadget);
if (retval)
@@ -3793,9 +3796,7 @@
pm_runtime_no_callbacks(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev);
- retval = register_trace_usb_daytona_invalid_access(dump_usb_info,
- NULL);
- if (retval)
+ if (register_trace_usb_daytona_invalid_access(dump_usb_info, NULL))
pr_err("Registering trace failed\n");
_udc = udc;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 87a3fd5..2f35315 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -728,12 +728,18 @@
rc = -EINTR;
break;
}
- if (common->thread_wakeup_needed)
+ spin_lock_irq(&common->lock);
+ if (common->thread_wakeup_needed) {
+ spin_unlock_irq(&common->lock);
break;
+ }
+ spin_unlock_irq(&common->lock);
schedule();
}
__set_current_state(TASK_RUNNING);
+ spin_lock_irq(&common->lock);
common->thread_wakeup_needed = 0;
+ spin_unlock_irq(&common->lock);
return rc;
}
@@ -796,12 +802,17 @@
curlun->file_length - file_offset);
/* Wait for the next buffer to become available */
+ spin_lock_irq(&common->lock);
bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
+ spin_unlock_irq(&common->lock);
rc = sleep_thread(common);
if (rc)
return rc;
+
+ spin_lock_irq(&common->lock);
}
+ spin_unlock_irq(&common->lock);
/*
* If we were asked to read past the end of file,
@@ -813,8 +824,10 @@
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
+ spin_lock_irq(&common->lock);
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
+ spin_unlock_irq(&common->lock);
break;
}
@@ -854,8 +867,10 @@
* equal to the buffer size, which is divisible by the
* bulk-in maxpacket size.
*/
+ spin_lock_irq(&common->lock);
bh->inreq->length = nread;
bh->state = BUF_STATE_FULL;
+ spin_unlock_irq(&common->lock);
/* If an error occurred, report it and its position */
if (nread < amount) {
@@ -1814,12 +1829,17 @@
u32 sd, sdinfo = 0;
/* Wait for the next buffer to become available */
+ spin_lock_irq(&common->lock);
bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
+ spin_unlock_irq(&common->lock);
rc = sleep_thread(common);
if (rc)
return rc;
+
+ spin_lock_irq(&common->lock);
}
+ spin_unlock_irq(&common->lock);
if (curlun) {
sd = curlun->sense_data;
@@ -2029,13 +2049,19 @@
dump_cdb(common);
/* Wait for the next buffer to become available for data or status */
+ spin_lock_irq(&common->lock);
bh = common->next_buffhd_to_fill;
common->next_buffhd_to_drain = bh;
while (bh->state != BUF_STATE_EMPTY) {
+ spin_unlock_irq(&common->lock);
rc = sleep_thread(common);
if (rc)
return rc;
+
+ spin_lock_irq(&common->lock);
}
+ spin_unlock_irq(&common->lock);
+
common->phase_error = 0;
common->short_packet_received = 0;
@@ -2376,12 +2402,17 @@
int rc = 0;
/* Wait for the next buffer to become available */
+ spin_lock_irq(&common->lock);
bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
+ spin_unlock_irq(&common->lock);
rc = sleep_thread(common);
if (rc)
return rc;
+
+ spin_lock_irq(&common->lock);
}
+ spin_unlock_irq(&common->lock);
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
@@ -2396,14 +2427,23 @@
*/
/* Wait for the CBW to arrive */
+ spin_lock_irq(&common->lock);
while (bh->state != BUF_STATE_FULL) {
+ spin_unlock_irq(&common->lock);
rc = sleep_thread(common);
if (rc)
return rc;
+
+ spin_lock_irq(&common->lock);
}
+ spin_unlock_irq(&common->lock);
+
smp_rmb();
rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+
+ spin_lock_irq(&common->lock);
bh->state = BUF_STATE_EMPTY;
+ spin_unlock_irq(&common->lock);
return rc;
}
@@ -2586,10 +2626,13 @@
/* Wait until everything is idle */
for (;;) {
int num_active = 0;
+ spin_lock_irq(&common->lock);
for (i = 0; i < fsg_num_buffers; ++i) {
bh = &common->buffhds[i];
num_active += bh->inreq_busy + bh->outreq_busy;
}
+ spin_unlock_irq(&common->lock);
+
if (num_active == 0)
break;
if (sleep_thread(common))
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index a1b02be..e48f94c 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -1497,6 +1497,11 @@
mbim->not_port.notify_req->context = mbim;
mbim->not_port.notify_req->complete = mbim_notify_complete;
+ if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
+ mbb_desc.wMaxSegmentSize = cpu_to_le16(0x800);
+ else
+ mbb_desc.wMaxSegmentSize = cpu_to_le16(0xfe0);
+
/* copy descriptors, and track endpoint copies */
f->descriptors = usb_copy_descriptors(mbim_fs_function);
if (!f->descriptors)
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0c0d58a..37189d8 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -50,7 +50,7 @@
#define STATE_ERROR 4 /* error from completion routine */
/* number of tx and rx requests to allocate */
-#define TX_REQ_MAX 4
+#define MTP_TX_REQ_MAX 8
#define RX_REQ_MAX 2
#define INTR_REQ_MAX 5
@@ -70,6 +70,12 @@
unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR);
+unsigned int mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
+module_param(mtp_tx_req_len, uint, S_IRUGO | S_IWUSR);
+
+unsigned int mtp_tx_reqs = MTP_TX_REQ_MAX;
+module_param(mtp_tx_reqs, uint, S_IRUGO | S_IWUSR);
+
static const char mtp_shortname[] = "mtp_usb";
struct mtp_dev {
@@ -488,11 +494,22 @@
ep->driver_data = dev; /* claim the endpoint */
dev->ep_intr = ep;
+retry_tx_alloc:
+ if (mtp_tx_req_len > MTP_BULK_BUFFER_SIZE)
+ mtp_tx_reqs = 4;
+
/* now allocate requests for our endpoints */
- for (i = 0; i < TX_REQ_MAX; i++) {
- req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE);
- if (!req)
- goto fail;
+ for (i = 0; i < mtp_tx_reqs; i++) {
+ req = mtp_request_new(dev->ep_in, mtp_tx_req_len);
+ if (!req) {
+ if (mtp_tx_req_len <= MTP_BULK_BUFFER_SIZE)
+ goto fail;
+ while ((req = mtp_req_get(dev, &dev->tx_idle)))
+ mtp_request_free(req, dev->ep_in);
+ mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
+ mtp_tx_reqs = MTP_TX_REQ_MAX;
+ goto retry_tx_alloc;
+ }
req->complete = mtp_complete_in;
mtp_req_put(dev, &dev->tx_idle, req);
}
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 5e68296..4f9cbf1 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -389,6 +389,7 @@
IPA_P_BAM : A2_P_BAM;
ecm_qc_bam_port.cdev = cdev;
+ ecm_qc_bam_port.func = &dev->port.func;
ecm_qc_bam_port.in = dev->port.in_ep;
ecm_qc_bam_port.out = dev->port.out_ep;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index baea664..267cf53 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -426,6 +426,7 @@
struct usb_gadget *gadget = cdev->gadget;
dev->bam_port.cdev = cdev;
+ dev->bam_port.func = &dev->port.func;
dev->bam_port.in = dev->port.in_ep;
dev->bam_port.out = dev->port.out_ep;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 1288bfd..32d4011 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -71,7 +71,7 @@
MODULE_PARM_DESC(rndis_multipacket_dl_disable,
"Disable RNDIS Multi-packet support in DownLink");
-static unsigned int rndis_ul_max_pkt_per_xfer = 1;
+static unsigned int rndis_ul_max_pkt_per_xfer = 3;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
"Maximum packets per transfer for UL aggregation");
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index bff7eb1..e662bfc 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1074,14 +1074,6 @@
struct sk_buff *skb2;
u32 msg_len, data_offset, data_len;
- /* some rndis hosts send extra byte to avoid zlp, ignore it */
- if (skb->len == 1) {
- if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
- rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
- dev_kfree_skb_any(skb);
- return 0;
- }
-
if (skb->len < sizeof *hdr) {
pr_err("invalid rndis pkt: skblen:%u hdr_len:%u",
skb->len, sizeof *hdr);
@@ -1115,7 +1107,8 @@
skb_pull(skb, data_offset + 8);
- if (msg_len == skb->len) {
+ if (data_len == skb->len ||
+ data_len == (skb->len - 1)) {
skb_trim(skb, data_len);
break;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index c05f683..b71f903 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -539,9 +539,12 @@
struct bam_ch_info *d = &port->data_ch;
int status;
- if (!port->port_usb)
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
return;
+ }
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
@@ -552,14 +555,69 @@
struct bam_ch_info *d = &port->data_ch;
int status;
- if (!port->port_usb)
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
return;
+ }
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
}
+static void gbam_stop_endless_rx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
+ return;
+ }
+ pr_debug("%s: dequeue\n", __func__);
+
+ status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void gbam_stop_endless_tx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
+ return;
+ }
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct gbam_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ gbam_start_endless_rx(port);
+ else
+ gbam_start_endless_tx(port);
+}
+
+static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct gbam_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ gbam_stop_endless_rx(port);
+ else
+ gbam_stop_endless_tx(port);
+}
+
static void gbam_start_io(struct gbam_port *port)
{
unsigned long flags;
@@ -1409,6 +1467,10 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
+ if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
+ usb_bam_suspend(&d->ipa_params);
+ }
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1426,4 +1488,6 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 2abe2ef..c638164 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -92,6 +92,7 @@
if (!port->port_usb)
return;
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing transfer, %d\n", status);
@@ -105,11 +106,40 @@
if (!port->port_usb)
return;
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing transfer, %d\n", status);
}
+static void bam_data_stop_endless_rx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb)
+ return;
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void bam_data_stop_endless_tx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb)
+ return;
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
static int bam_data_peer_reset_cb(void *param)
{
struct bam_data_port *port = (struct bam_data_port *)param;
@@ -148,6 +178,15 @@
reenable_eps:
/* Re-Enable the relevant EPs, if EPs were originally enabled */
if (reenable_eps) {
+ if (config_ep_by_speed(port->port_usb->cdev->gadget,
+ port->port_usb->func, port->port_usb->in) ||
+ config_ep_by_speed(port->port_usb->cdev->gadget,
+ port->port_usb->func, port->port_usb->out)) {
+ pr_err("%s: config_ep_by_speed failed", __func__);
+ port->port_usb->in->desc = NULL;
+ port->port_usb->out->desc = NULL;
+ return -EINVAL;
+ }
ret = usb_ep_enable(port->port_usb->in);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
@@ -529,9 +568,28 @@
return usb_gadget_wakeup(d_port->cdev->gadget);
}
+static void bam_data_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct bam_data_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ bam_data_start_endless_rx(port);
+ else
+ bam_data_start_endless_tx(port);
+}
+
+static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct bam_data_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ bam_data_stop_endless_rx(port);
+ else
+ bam_data_stop_endless_tx(port);
+}
+
void bam_data_suspend(u8 port_num)
{
-
struct bam_data_port *port;
struct bam_data_ch_info *d;
@@ -540,6 +598,11 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
+ port);
+ usb_bam_suspend(&d->ipa_params);
+ }
}
void bam_data_resume(u8 port_num)
@@ -553,5 +616,6 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
}
-
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 486191b5..5ce678d 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -23,6 +23,7 @@
struct data_port {
struct usb_composite_dev *cdev;
+ struct usb_function *func;
struct usb_ep *in;
struct usb_ep *out;
};
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ede8bdb..c5304e1 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -752,6 +752,19 @@
return -EBUSY;
}
+ if (pdata->consider_ipa_handshake) {
+ dev_dbg(mehci->dev, "%s:Wait for resources release\n",
+ __func__);
+ if (!msm_bam_hsic_lpm_ok()) {
+ dev_dbg(mehci->dev, "%s:Prod+Cons not released\n",
+ __func__);
+ enable_irq(hcd->irq);
+ return -EBUSY;
+ }
+ dev_dbg(mehci->dev, "%s:Prod+Cons resources released\n",
+ __func__);
+ }
+
/*
* PHY may take some time or even fail to enter into low power
* mode (LPM). Hence poll for 500 msec and reset the PHY and link
@@ -829,7 +842,7 @@
wake_unlock(&mehci->wlock);
- dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
+ dev_info(mehci->dev, "HSIC-USB in low power mode\n");
return 0;
}
@@ -848,6 +861,14 @@
return 0;
}
+ if (pdata->consider_ipa_handshake) {
+ dev_dbg(mehci->dev, "%s:Wait for producer resource\n",
+ __func__);
+ msm_bam_wait_for_hsic_prod_granted();
+ dev_dbg(mehci->dev, "%s:Producer resource obtained\n",
+ __func__);
+ }
+
/* Handles race with Async interrupt */
disable_irq(hcd->irq);
@@ -933,7 +954,13 @@
}
enable_irq(hcd->irq);
- dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
+ dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
+
+ if (pdata->consider_ipa_handshake) {
+ dev_dbg(mehci->dev, "%s:Notify usb bam on resume complete\n",
+ __func__);
+ msm_bam_hsic_notify_on_resume();
+ }
return 0;
}
@@ -1035,6 +1062,7 @@
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
int retval;
mehci->timer = USB_HS_GPTIMER_BASE;
@@ -1065,8 +1093,14 @@
/* bursts of unspecified length. */
writel_relaxed(0, USB_AHBBURST);
- /* Use the AHB transactor */
- writel_relaxed(0x08, USB_AHBMODE);
+
+ /* Use the AHB transactor and configure async bridge bypass */
+#define MSM_USB_ASYNC_BRIDGE_BYPASS BIT(31)
+ if (pdata->ahb_async_bridge_bypass)
+ writel_relaxed(0x08 | MSM_USB_ASYNC_BRIDGE_BYPASS, USB_AHBMODE);
+ else
+ writel_relaxed(0x08, USB_AHBMODE);
+
/* Disable streaming mode and select host mode */
writel_relaxed(0x13, USB_USBMODE);
@@ -1853,6 +1887,10 @@
"qcom,enable-hbm");
pdata->disable_park_mode = (of_property_read_bool(node,
"qcom,disable-park-mode"));
+ pdata->consider_ipa_handshake = (of_property_read_bool(node,
+ "hsic,consider-ipa-handshake"));
+ pdata->ahb_async_bridge_bypass = of_property_read_bool(node,
+ "qcom,ahb-async-bridge-bypass");
return pdata;
}
@@ -2092,6 +2130,8 @@
if (mehci->enable_hbm)
hbm_init(hcd, pdata->disable_park_mode);
+ msm_bam_set_hsic_host_dev(&pdev->dev);
+
return 0;
destroy_wq:
@@ -2115,6 +2155,8 @@
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+ msm_bam_set_hsic_host_dev(NULL);
+
/* If the device was removed no need to call pm_runtime_disable */
if (pdev->dev.power.power_state.event != PM_EVENT_INVALID)
pm_runtime_disable(&pdev->dev);
@@ -2180,7 +2222,6 @@
#ifdef CONFIG_PM_SLEEP
static int msm_hsic_pm_suspend(struct device *dev)
{
- int ret;
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -2188,15 +2229,16 @@
dbg_log_event(NULL, "PM Suspend", 0);
+ if (!atomic_read(&mehci->in_lpm)) {
+ dev_info(dev, "abort suspend\n");
+ dbg_log_event(NULL, "PM Suspend abort", 0);
+ return -EBUSY;
+ }
+
if (device_may_wakeup(dev) && !mehci->async_irq)
enable_irq_wake(hcd->irq);
- ret = msm_hsic_suspend(mehci);
-
- if (ret && device_may_wakeup(dev) && !mehci->async_irq)
- disable_irq_wake(hcd->irq);
-
- return ret;
+ return 0;
}
static int msm_hsic_pm_suspend_noirq(struct device *dev)
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index d4d7ee9..44a7aee 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -861,7 +861,7 @@
struct usb_bus *bus = phy->otg->host;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
- bool host_bus_suspend, device_bus_suspend, dcp;
+ bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc;
@@ -870,7 +870,7 @@
return 0;
if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
- return 0;
+ return -EBUSY;
disable_irq(motg->irq);
host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
@@ -879,6 +879,7 @@
test_bit(A_BUS_SUSPEND, &motg->inputs) &&
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
+ prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
/*
* Abort suspend when,
@@ -887,7 +888,7 @@
*/
if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
- !dcp) || test_bit(A_BUS_REQ, &motg->inputs)) {
+ !dcp && !prop_charger) || test_bit(A_BUS_REQ, &motg->inputs)) {
enable_irq(motg->irq);
return -EBUSY;
}
@@ -955,7 +956,7 @@
*/
cmd_val = readl_relaxed(USB_USBCMD);
if (host_bus_suspend || device_bus_suspend ||
- (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
+ (motg->pdata->otg_control == OTG_PHY_CONTROL))
cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
else
cmd_val |= ULPI_STP_CTRL;
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index e46ea3b..bb5d3ca 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -104,8 +104,14 @@
kfree(panel_private->on_cmds);
kfree(panel_private->off_cmds);
+
kfree(panel_private);
panel_private = NULL;
+
+ if (bl_led_trigger) {
+ led_trigger_unregister_simple(bl_led_trigger);
+ bl_led_trigger = NULL;
+ }
}
int dsi_panel_power(int enable)
{
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 5223e66..65c9e90 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -290,12 +290,16 @@
static void mdp3_bus_scale_unregister(void)
{
int i;
+
+ if (!mdp3_res->bus_handle)
+ return;
+
for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
pr_debug("unregister index=%d bus_handle=%x\n",
i, mdp3_res->bus_handle[i].handle);
if (mdp3_res->bus_handle[i].handle) {
msm_bus_scale_unregister_client(
- mdp3_res->bus_handle[i].handle);
+ mdp3_res->bus_handle[i].handle);
mdp3_res->bus_handle[i].handle = 0;
}
}
@@ -484,11 +488,20 @@
static void mdp3_clk_remove(void)
{
- clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
- clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
- clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
- clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
- clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_AHB]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_CORE]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_VSYNC]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_LCDC]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_DSI]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
}
int mdp3_clk_enable(int enable)
@@ -519,6 +532,7 @@
return ret;
}
disable_irq(mdp3_res->irq);
+ mdp3_res->irq_registered = true;
return 0;
}
@@ -556,7 +570,8 @@
struct mdp3_iommu_ctx_map *context_map;
struct mdp3_iommu_domain_map *domain_map;
- if (context >= MDP3_IOMMU_CTX_MAX)
+ if (!mdp3_res->iommu_contexts ||
+ context >= MDP3_IOMMU_CTX_MAX)
return -EINVAL;
context_map = mdp3_res->iommu_contexts + context;
@@ -595,10 +610,13 @@
mdp3_iommu_domains[i].domain_idx = domain_idx;
mdp3_iommu_domains[i].domain = msm_get_iommu_domain(domain_idx);
- if (!mdp3_iommu_domains[i].domain) {
+ if (IS_ERR_OR_NULL(mdp3_iommu_domains[i].domain)) {
pr_err("unable to get iommu domain(%d)\n",
domain_idx);
- return -EINVAL;
+ if (!mdp3_iommu_domains[i].domain)
+ return -EINVAL;
+ else
+ return PTR_ERR(mdp3_iommu_domains[i].domain);
}
iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
mdp3_iommu_fault_handler,
@@ -623,10 +641,13 @@
mdp3_iommu_contexts[i].ctx =
msm_iommu_get_ctx(mdp3_iommu_contexts[i].ctx_name);
- if (!mdp3_iommu_contexts[i].ctx) {
+ if (IS_ERR_OR_NULL(mdp3_iommu_contexts[i].ctx)) {
pr_warn("unable to get iommu ctx(%s)\n",
mdp3_iommu_contexts[i].ctx_name);
- return -EINVAL;
+ if (!mdp3_iommu_contexts[i].ctx)
+ return -EINVAL;
+ else
+ return PTR_ERR(mdp3_iommu_contexts[i].ctx);
}
}
@@ -653,6 +674,19 @@
return ret;
}
+void mdp3_iommu_deinit(void)
+{
+ int i;
+
+ if (!mdp3_res->domains)
+ return;
+
+ for (i = 0; i < MDP3_IOMMU_DOMAIN_MAX; i++) {
+ if (!IS_ERR_OR_NULL(mdp3_res->domains[i].domain))
+ msm_unregister_domain(mdp3_res->domains[i].domain);
+ }
+}
+
static int mdp3_check_version(void)
{
int rc;
@@ -742,6 +776,21 @@
return rc;
}
+static void mdp3_res_deinit(void)
+{
+ mdp3_bus_scale_unregister();
+ mdp3_iommu_dettach(MDP3_IOMMU_CTX_DMA_0);
+ mdp3_iommu_deinit();
+
+ if (!IS_ERR_OR_NULL(mdp3_res->ion_client))
+ ion_client_destroy(mdp3_res->ion_client);
+
+ mdp3_clk_remove();
+
+ if (mdp3_res->irq_registered)
+ devm_free_irq(&mdp3_res->pdev->dev, mdp3_res->irq, mdp3_res);
+}
+
static int mdp3_parse_dt(struct platform_device *pdev)
{
struct resource *res;
@@ -847,7 +896,10 @@
data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
pr_err("error on ion_import_fd\n");
- ret = PTR_ERR(data->srcp_ihdl);
+ if (!data->srcp_ihdl)
+ ret = -EINVAL;
+ else
+ ret = PTR_ERR(data->srcp_ihdl);
data->srcp_ihdl = NULL;
return ret;
}
@@ -1002,6 +1054,11 @@
probe_done:
if (IS_ERR_VALUE(rc)) {
+ mdp3_res_deinit();
+
+ if (mdp3_res->mdp_base)
+ devm_iounmap(&pdev->dev, mdp3_res->mdp_base);
+
devm_kfree(&pdev->dev, mdp3_res);
mdp3_res = NULL;
}
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 878fe25..e52f7bc 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -119,6 +119,8 @@
u32 irq_mask;
struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
+ int irq_registered;
+
struct early_suspend suspend_handler;
};
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 3d990c2..037ab51 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -24,6 +24,7 @@
#include "mdp3.h"
#include "mdp3_ppp.h"
+#define MDP_CORE_CLK_RATE 100000000
#define MDP_VSYNC_CLK_RATE 19200000
#define VSYNC_PERIOD 16
@@ -191,13 +192,9 @@
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
- rc = wait_for_completion_interruptible_timeout(
- &mdp3_session->vsync_comp,
- msecs_to_jiffies(VSYNC_PERIOD * 5));
- if (rc <= 0) {
- pr_warn("vsync wait on fb%d interrupted (%d)\n",
- mfd->index, rc);
- }
+ rc = wait_for_completion_interruptible(&mdp3_session->vsync_comp);
+ if (rc < 0)
+ return rc;
spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
@@ -240,17 +237,8 @@
{
int rc = 0;
if (status) {
- struct mdss_panel_info *panel_info = mfd->panel_info;
- unsigned long core_clk;
- int vtotal;
- vtotal = panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres;
- core_clk = panel_info->xres * panel_info->yres;
- core_clk *= panel_info->mipi.frame_rate;
- core_clk = (core_clk / panel_info->yres) * vtotal;
- mdp3_clk_set_rate(MDP3_CLK_CORE, core_clk);
+
+ mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE);
mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE);
rc = mdp3_clk_enable(true);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index a09f503..fa2e9eb 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -218,7 +218,7 @@
* NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
* the default 16 for MDP hang issue workaround
*/
- MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x10);
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
dma->source_config = *source_config;
@@ -809,6 +809,7 @@
temp |= BIT(2);
MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_CTL_POLARITY, temp);
+ MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL, 0x800000ff);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index c663170..afabc20 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -418,6 +418,9 @@
/* disable DSI phy */
mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
+
+ mdss_dsi_disable_bus_clocks(ctrl_pdata);
+
ret = mdss_dsi_panel_power_on(pdata, 0);
if (ret) {
pr_err("%s: Panel power off failed\n", __func__);
@@ -429,42 +432,6 @@
return ret;
}
-int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
-{
- int ret = 0;
- struct mipi_panel_info *mipi;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
- pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
-
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- mipi = &pdata->panel_info.mipi;
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
- ctrl_pdata, ctrl_pdata->ndx);
-
- WARN(ctrl_pdata->panel_state != UNKNOWN_STATE,
- "incorrect panel state=%d\n", ctrl_pdata->panel_state);
-
- mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
-
- mdss_dsi_op_mode_config(mipi->mode, pdata);
-
- ctrl_pdata->panel_state = PANEL_ON;
-
- pr_debug("%s-:End\n", __func__);
- return ret;
-}
-
-
int mdss_dsi_on(struct mdss_panel_data *pdata)
{
int ret = 0;
@@ -502,6 +469,14 @@
pdata->panel_info.panel_power_on = 1;
+ ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
+ if (ret) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+ ret);
+ mdss_dsi_panel_power_on(pdata, 0);
+ return ret;
+ }
+
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
@@ -607,14 +582,14 @@
panel_data);
mipi = &pdata->panel_info.mipi;
- if (ctrl_pdata->panel_state != PANEL_ON) {
+ if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
ret = ctrl_pdata->on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel\n",
__func__);
return ret;
}
- ctrl_pdata->panel_state = PANEL_ON;
+ ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
mdss_dsi_op_mode_config(mipi->mode, pdata);
@@ -640,18 +615,58 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
- if (ctrl_pdata->panel_state == PANEL_ON) {
+ if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
ret = ctrl_pdata->off(pdata);
if (ret) {
pr_err("%s: Panel OFF failed\n", __func__);
return ret;
}
- ctrl_pdata->panel_state = PANEL_OFF;
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
}
pr_debug("%s-:End\n", __func__);
return ret;
}
+int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ mipi = &pdata->panel_info.mipi;
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+ ctrl_pdata, ctrl_pdata->ndx);
+
+ WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT),
+ "Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
+
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(mipi, pdata);
+
+ if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
+ mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+ ret = mdss_dsi_unblank(pdata);
+ if (ret) {
+ pr_err("%s: unblank failed\n", __func__);
+ return ret;
+ }
+ }
+
+ pr_debug("%s-:End\n", __func__);
+ return ret;
+}
+
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@@ -673,6 +688,7 @@
rc = mdss_dsi_unblank(pdata);
break;
case MDSS_EVENT_PANEL_ON:
+ ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_unblank(pdata);
break;
@@ -681,11 +697,13 @@
rc = mdss_dsi_blank(pdata);
break;
case MDSS_EVENT_PANEL_OFF:
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_blank(pdata);
rc = mdss_dsi_off(pdata);
break;
case MDSS_EVENT_CONT_SPLASH_FINISH:
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
rc = mdss_dsi_cont_splash_on(pdata);
} else {
@@ -701,6 +719,12 @@
case MDSS_EVENT_DSI_CMDLIST_KOFF:
mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
break;
+ case MDSS_EVENT_CONT_SPLASH_BEGIN:
+ if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) {
+ /* Panel is Enabled in Bootloader */
+ rc = mdss_dsi_blank(pdata);
+ }
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -1094,6 +1118,12 @@
* register in mdp driver
*/
+ ctrl_pdata->pclk_rate = dsi_pclk_rate;
+ ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+ pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+ ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+
+ ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN;
cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
"qcom,cont-splash-enabled");
if (!cont_splash_enabled) {
@@ -1112,15 +1142,20 @@
pr_err("%s: Panel power on failed\n", __func__);
return rc;
}
- }
- ctrl_pdata->pclk_rate = dsi_pclk_rate;
- ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
- pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
- ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+ rc = mdss_dsi_enable_bus_clocks(ctrl_pdata);
+ if (rc) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n",
+ __func__, rc);
+ rc = mdss_dsi_panel_power_on(
+ &(ctrl_pdata->panel_data), 0);
+ return rc;
+ }
- if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled)
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ ctrl_pdata->ctrl_state |=
+ (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
+ }
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
@@ -1145,7 +1180,6 @@
ctrl_pdata->ndx = 1;
}
- ctrl_pdata->panel_state = UNKNOWN_STATE;
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 602ed9e..f612751 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -84,16 +84,14 @@
UNKNOWN_CTRL,
};
-enum dsi_ctrl_state {
+enum dsi_ctrl_op_mode {
DSI_LP_MODE,
DSI_HS_MODE,
};
-enum dsi_panel_state {
- UNKNOWN_STATE,
- PANEL_ON,
- PANEL_OFF,
-};
+#define CTRL_STATE_UNKNOWN 0x00
+#define CTRL_STATE_PANEL_INIT BIT(0)
+#define CTRL_STATE_MDP_ACTIVE BIT(1)
#define DSI_NON_BURST_SYNCH_PULSE 0
#define DSI_NON_BURST_SYNCH_EVENT 1
@@ -327,10 +325,12 @@
unsigned char *ctrl_base;
int reg_size;
u32 clk_cnt;
+ struct clk *ahb_clk;
+ struct clk *axi_clk;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
- u8 panel_state;
+ u8 ctrl_state;
int irq_cnt;
int mdss_dsi_clk_on;
int rst_gpio;
@@ -409,6 +409,8 @@
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_unprepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 6b0f68e..05a84e3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -189,6 +189,12 @@
msleep(20);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+ if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
+ pr_debug("%s: Panel Not properly turned OFF\n",
+ __func__);
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
+ pr_debug("%s: Reset panel done\n", __func__);
+ }
} else {
gpio_set_value((ctrl_pdata->rst_gpio), 0);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e2d8cf6..5445137 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1725,7 +1725,7 @@
if (!mdp_instance) {
pr_err("mdss mdp resource not initialized yet\n");
- return -ENODEV;
+ return -EPROBE_DEFER;
}
node = of_parse_phandle(pdev->dev.of_node, "qcom,mdss-fb-map", 0);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index f726e79..1f0efd3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013 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
@@ -287,7 +287,7 @@
timeout_count = 100;
keys_state = (link0_status >> 28) & 0x7;
while ((keys_state != HDCP_KEYS_STATE_VALID) &&
- timeout_count--) {
+ --timeout_count) {
link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
keys_state = (link0_status >> 28) & 0x7;
DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x",
@@ -320,7 +320,7 @@
link0_status);
msleep(20);
}
- } while (!an_ready && timeout_count--);
+ } while (!an_ready && --timeout_count);
if (!timeout_count) {
rc = -ETIMEDOUT;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index ab91320..fe10189 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -614,6 +614,37 @@
}
} /* hdmi_tx_set_audio_switch_node */
+static int hdmi_tx_config_avmute(struct hdmi_tx_ctrl *hdmi_ctrl, int set)
+{
+ struct dss_io_data *io;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ if (set)
+ DSS_REG_W(io, HDMI_GC,
+ DSS_REG_R(io, HDMI_GC) | BIT(0));
+ else
+ DSS_REG_W(io, HDMI_GC,
+ DSS_REG_R(io, HDMI_GC) & ~BIT(0));
+
+ /* Enable AV Mute tranmission here */
+ DSS_REG_W(io, HDMI_VBI_PKT_CTRL,
+ DSS_REG_R(io, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5)));
+
+ DEV_DBG("%s: AVMUTE %s\n", __func__, set ? "set" : "cleared");
+
+ return 0;
+} /* hdmi_tx_config_avmute */
+
void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status)
{
int rc = 0;
@@ -629,13 +660,25 @@
switch (status) {
case HDCP_STATE_AUTHENTICATED:
- if (hdmi_ctrl->hpd_state)
+ if (hdmi_ctrl->hpd_state) {
+ /* Clear AV Mute */
+ rc = hdmi_tx_config_avmute(hdmi_ctrl, 0);
+ if (rc)
+ DEV_ERR("%s: Failed to clear av mute. rc=%d\n",
+ __func__, rc);
hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false);
+ }
break;
case HDCP_STATE_AUTH_FAIL:
hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
if (hdmi_ctrl->hpd_state) {
+ /* Set AV Mute */
+ rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);
+ if (rc)
+ DEV_ERR("%s: Failed to set av mute. rc=%d\n",
+ __func__, rc);
+
DEV_DBG("%s: Reauthenticating\n", __func__);
rc = hdmi_hdcp_reauthenticate(
hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
@@ -2743,6 +2786,12 @@
case MDSS_EVENT_PANEL_ON:
if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
+ /* Set AV Mute before starting authentication */
+ rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);
+ if (rc)
+ DEV_ERR("%s: Failed to set av mute. rc=%d\n",
+ __func__, rc);
+
DEV_DBG("%s: Starting HDCP authentication\n", __func__);
rc = hdmi_hdcp_authenticate(
hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index e346082..4b763aa 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1505,7 +1505,6 @@
mdss_mdp_pp_setup_locked(ctl);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
- mdss_mdp_pp_setup_locked(sctl);
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
sctl->flush_bits);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 72cbed9..ab028e4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -562,6 +562,13 @@
pdata->panel_info.cont_splash_enabled = 0;
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
+ NULL);
+ if (ret) {
+ pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n",
+ __func__);
+ return ret;
+ }
mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c96464a..4a03e13 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1286,20 +1286,14 @@
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
unsigned long flags;
u64 vsync_ticks;
- unsigned long timeout;
int ret;
if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
return 0;
- timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
- ret = wait_for_completion_interruptible_timeout(&mdp5_data->vsync_comp,
- timeout);
- if (ret <= 0) {
- pr_debug("Sending current time as vsync timestamp for fb%d\n",
- mfd->index);
- mdp5_data->vsync_time = ktime_get();
- }
+ ret = wait_for_completion_interruptible(&mdp5_data->vsync_comp);
+ if (ret < 0)
+ return ret;
spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index fcc1c1a..9d28265 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -888,14 +888,19 @@
return ret;
}
-static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+static int pp_mixer_setup(u32 disp_num,
struct mdss_mdp_mixer *mixer)
{
u32 flags, offset, dspp_num, opmode = 0;
struct mdp_pgc_lut_data *pgc_config;
struct pp_sts_type *pp_sts;
+ struct mdss_mdp_ctl *ctl;
dspp_num = mixer->num;
+ if (!mixer || !mixer->ctl)
+ return -EINVAL;
+ ctl = mixer->ctl;
+
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
@@ -1003,8 +1008,7 @@
return ret;
}
-static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
- struct mdss_mdp_mixer *mixer)
+static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
{
u32 flags, base, offset, dspp_num, opmode = 0;
struct mdp_dither_cfg_data *dither_cfg;
@@ -1014,12 +1018,12 @@
char __iomem *basel;
int i, ret = 0;
struct mdss_data_type *mdata;
+ struct mdss_mdp_ctl *ctl;
- mdata = ctl->mdata;
-
- if (!mixer || !ctl || !mdata)
+ if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
return -EINVAL;
-
+ ctl = mixer->ctl;
+ mdata = ctl->mdata;
dspp_num = mixer->num;
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
@@ -1174,12 +1178,12 @@
mutex_lock(&mdss_pp_mutex);
if (ctl->mixer_left) {
- pp_mixer_setup(disp_num, ctl, ctl->mixer_left);
- pp_dspp_setup(disp_num, ctl, ctl->mixer_left);
+ pp_mixer_setup(disp_num, ctl->mixer_left);
+ pp_dspp_setup(disp_num, ctl->mixer_left);
}
if (ctl->mixer_right) {
- pp_mixer_setup(disp_num, ctl, ctl->mixer_right);
- pp_dspp_setup(disp_num, ctl, ctl->mixer_right);
+ pp_mixer_setup(disp_num, ctl->mixer_right);
+ pp_dspp_setup(disp_num, ctl->mixer_right);
}
/* clear dirty flag */
if (disp_num < MDSS_BLOCK_DISP_NUM)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index f138420..1bf414f 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -76,8 +76,13 @@
* - negative if the configuration is invalid
* - 0 if there is no panel reconfig needed
* - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_BEGIN: Special event used to handle transition of
+ * display state from boot loader to panel driver.
+ * The event handler will disable the panel.
* @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
* display state from boot loader to panel driver.
+ * The event handler will enable the panel and
+ * vote for the display clocks.
* @MDSS_EVENT_FB_REGISTERED: Called after fb dev driver has been registered,
* panel driver gets ptr to struct fb_info which
* holds fb dev information.
@@ -96,6 +101,7 @@
MDSS_EVENT_SUSPEND,
MDSS_EVENT_RESUME,
MDSS_EVENT_CHECK_PARAMS,
+ MDSS_EVENT_CONT_SPLASH_BEGIN,
MDSS_EVENT_CONT_SPLASH_FINISH,
MDSS_EVENT_FB_REGISTERED,
MDSS_EVENT_PANEL_CLK_CTRL,
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 08d0693..15811bb 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -201,6 +201,22 @@
return 0;
}
+int mhl_msc_clear(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ if (!mhl_ctrl)
+ return -EFAULT;
+
+ memset(mhl_ctrl->devcap, 0, 16);
+ mhl_ctrl->devcap_state = 0;
+ mhl_ctrl->path_en_state = 0;
+ mhl_ctrl->status[0] = 0;
+ mhl_ctrl->status[1] = 0;
+ mhl_ctrl->scrpd_busy = 0;
+ mhl_ctrl->wr_burst_pending = 0;
+
+ return 0;
+}
+
int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
struct msc_command_struct *req)
{
@@ -541,7 +557,7 @@
* connected device bits
* changed and DEVCAP READY
*/
- if (((value ^ mhl_ctrl->devcap_state) &
+ if (((value ^ mhl_ctrl->status[offset]) &
MHL_STATUS_DCAP_RDY)) {
if (value & MHL_STATUS_DCAP_RDY) {
mhl_ctrl->devcap_state = 0;
@@ -563,7 +579,7 @@
* bit set
*/
tmds_en = mhl_check_tmds_enabled(mhl_ctrl);
- if ((value ^ mhl_ctrl->path_en_state)
+ if ((value ^ mhl_ctrl->status[offset])
& MHL_STATUS_PATH_ENABLED) {
if (value & MHL_STATUS_PATH_ENABLED) {
if (tmds_en &&
@@ -593,7 +609,7 @@
}
break;
}
- mhl_ctrl->path_en_state = value;
+ mhl_ctrl->status[offset] = value;
return 0;
}
diff --git a/drivers/video/msm/mdss/mhl_msc.h b/drivers/video/msm/mdss/mhl_msc.h
index 8a1fd39..3137f17 100644
--- a/drivers/video/msm/mdss/mhl_msc.h
+++ b/drivers/video/msm/mdss/mhl_msc.h
@@ -25,6 +25,8 @@
/******************************************************************/
/* the below APIs are implemented by the MSC functionality */
+int mhl_msc_clear(struct mhl_tx_ctrl *mhl_ctrl);
+
int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
struct msc_command_struct *req);
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 3c11317..a1053fb 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -867,6 +867,7 @@
/* disabling Tx termination */
MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+ mhl_msc_clear(mhl_ctrl);
}
static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 12bc5e0..d4eb716 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -32,6 +32,7 @@
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
struct device *dev = NULL;
+ int rc = 0;
if (!pdev) {
pr_err("%s: Invalid pdev\n", __func__);
@@ -39,32 +40,53 @@
}
dev = &pdev->dev;
+ ctrl_pdata->ahb_clk = clk_get(dev, "iface_clk");
+ if (IS_ERR(ctrl_pdata->ahb_clk)) {
+ rc = PTR_ERR(ctrl_pdata->ahb_clk);
+ pr_err("%s: Unable to get mdss ahb clk. rc=%d\n",
+ __func__, rc);
+ goto mdss_dsi_clk_err;
+ }
+
+ ctrl_pdata->axi_clk = clk_get(dev, "bus_clk");
+ if (IS_ERR(ctrl_pdata->axi_clk)) {
+ rc = PTR_ERR(ctrl_pdata->axi_clk);
+ pr_err("%s: Unable to get axi bus clk. rc=%d\n",
+ __func__, rc);
+ goto mdss_dsi_clk_err;
+ }
+
ctrl_pdata->byte_clk = clk_get(dev, "byte_clk");
if (IS_ERR(ctrl_pdata->byte_clk)) {
- pr_err("can't find dsi_byte_clk\n");
+ rc = PTR_ERR(ctrl_pdata->byte_clk);
+ pr_err("%s: can't find dsi_byte_clk. rc=%d\n",
+ __func__, rc);
ctrl_pdata->byte_clk = NULL;
goto mdss_dsi_clk_err;
}
ctrl_pdata->pixel_clk = clk_get(dev, "pixel_clk");
if (IS_ERR(ctrl_pdata->pixel_clk)) {
- pr_err("can't find dsi_pixel_clk\n");
+ rc = PTR_ERR(ctrl_pdata->pixel_clk);
+ pr_err("%s: can't find dsi_pixel_clk. rc=%d\n",
+ __func__, rc);
ctrl_pdata->pixel_clk = NULL;
goto mdss_dsi_clk_err;
}
ctrl_pdata->esc_clk = clk_get(dev, "core_clk");
if (IS_ERR(ctrl_pdata->esc_clk)) {
- pr_err("can't find dsi_esc_clk\n");
+ rc = PTR_ERR(ctrl_pdata->esc_clk);
+ pr_err("%s: can't find dsi_esc_clk. rc=%d\n",
+ __func__, rc);
ctrl_pdata->esc_clk = NULL;
goto mdss_dsi_clk_err;
}
- return 0;
-
mdss_dsi_clk_err:
- mdss_dsi_clk_deinit(ctrl_pdata);
- return -EPERM;
+ if (rc)
+ mdss_dsi_clk_deinit(ctrl_pdata);
+ return rc;
}
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -75,6 +97,10 @@
clk_put(ctrl_pdata->esc_clk);
if (ctrl_pdata->pixel_clk)
clk_put(ctrl_pdata->pixel_clk);
+ if (ctrl_pdata->axi_clk)
+ clk_put(ctrl_pdata->axi_clk);
+ if (ctrl_pdata->ahb_clk)
+ clk_put(ctrl_pdata->ahb_clk);
}
#define PREF_DIV_RATIO 27
@@ -156,6 +182,33 @@
return 0;
}
+int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int rc = 0;
+
+ rc = clk_prepare_enable(ctrl_pdata->ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+ goto error;
+ }
+
+ rc = clk_prepare_enable(ctrl_pdata->axi_clk);
+ if (rc) {
+ pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+ clk_disable_unprepare(ctrl_pdata->ahb_clk);
+ goto error;
+ }
+
+error:
+ return rc;
+}
+
+void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ clk_disable_unprepare(ctrl_pdata->axi_clk);
+ clk_disable_unprepare(ctrl_pdata->ahb_clk);
+}
+
void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
clk_prepare(ctrl_pdata->byte_clk);
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index aa1eba5..ce9e5b9 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -195,7 +195,7 @@
/* write pointer offset in bytes */
unsigned int write_offset;
- /* non-zero if data error occured */
+ /* non-zero if data error occurred */
int error;
};
@@ -237,7 +237,10 @@
* (dmx_sct_filter_params) and no sections were
* received for the given time.
*/
- DMX_EVENT_SECTION_TIMEOUT = 0x00000400
+ DMX_EVENT_SECTION_TIMEOUT = 0x00000400,
+
+ /* Scrambling bits change between clear and scrambled */
+ DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800
};
enum dmx_oob_cmd {
@@ -256,7 +259,7 @@
/* Discontinuity indicator was set */
#define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02
-/* PES legnth in PES header is not correct */
+/* PES length in PES header is not correct */
#define DMX_FILTER_PES_LENGTH_ERROR 0x04
@@ -412,7 +415,7 @@
/*
* The PID the index entry belongs to.
* In case of recording filter, multiple PIDs may exist in the same
- * filter through DMX_ADD_PID ioctl and each can be indexed seperatly.
+ * filter through DMX_ADD_PID ioctl and each can be indexed separately.
*/
__u16 pid;
@@ -423,7 +426,7 @@
__u64 match_tsp_num;
/*
- * The TS packet number in the recorded data preceeding
+ * The TS packet number in the recorded data preceding
* match_tsp_num and has PUSI set.
*/
__u64 last_pusi_tsp_num;
@@ -432,6 +435,23 @@
__u64 stc;
};
+/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */
+struct dmx_scrambling_status_event_info {
+ /*
+ * The PID which its scrambling bit status changed.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have
+ * different scrambling bits status.
+ */
+ __u16 pid;
+
+ /* old value of scrambling bits */
+ __u8 old_value;
+
+ /* new value of scrambling bits */
+ __u8 new_value;
+};
+
/*
* Filter's event returned through DMX_GET_EVENT.
* poll with POLLPRI would block until events are available.
@@ -447,6 +467,7 @@
struct dmx_es_data_event_info es_data;
struct dmx_marker_event_info marker;
struct dmx_index_event_info index;
+ struct dmx_scrambling_status_event_info scrambling_status;
} params;
};
@@ -754,6 +775,19 @@
__u32 identifier;
};
+struct dmx_scrambling_bits {
+ /*
+ * The PID to return its scrambling bit value.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have different
+ * scrambling bits status.
+ */
+ __u16 pid;
+
+ /* Current value of scrambling bits: 0, 1, 2 or 3 */
+ __u8 value;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -784,5 +818,6 @@
#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
+#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index df9569b..47a2b7b 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -18,10 +18,10 @@
#define FCC_CC_COLS 5
#define FCC_TEMP_COLS 8
-#define PC_CC_ROWS 29
+#define PC_CC_ROWS 31
#define PC_CC_COLS 13
-#define PC_TEMP_ROWS 29
+#define PC_TEMP_ROWS 31
#define PC_TEMP_COLS 8
#define MAX_SINGLE_LUT_COLS 20
@@ -74,6 +74,7 @@
BATT_PALLADIUM,
BATT_DESAY,
BATT_OEM,
+ BATT_QRD_4V35_2000MAH,
};
/**
@@ -114,6 +115,7 @@
extern struct bms_battery_data palladium_1500_data;
extern struct bms_battery_data desay_5200_data;
extern struct bms_battery_data oem_batt_data;
+extern struct bms_battery_data QRD_4v35_2000mAh_data;
int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp);
int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc);
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index a66a411..f04bf80 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -146,6 +146,7 @@
struct completion msc_cmd_done;
uint8_t devcap[16];
uint8_t devcap_state;
+ uint8_t status[2];
uint8_t path_en_state;
void *hdmi_mhl_ops;
struct work_struct mhl_msc_send_work;
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 3d159c4..a741107 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -72,6 +72,13 @@
uint16_t gain;
};
+enum msm_spkr_prot_states {
+ MSM_SPKR_PROT_CALIBRATED,
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS,
+ MSM_SPKR_PROT_DISABLED,
+ MSM_SPKR_PROT_NOT_CALIBRATED
+};
+
struct msm_spk_prot_cfg {
int r0;
int t0;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index e8de769..ae88807 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -781,6 +781,27 @@
#define IOCTL_KGSL_PERFCOUNTER_READ \
_IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
+/*
+ * struct kgsl_gpumem_sync_cache_bulk - argument to
+ * IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK
+ * @id_list: list of GPU buffer ids of the buffers to sync
+ * @count: number of GPU buffer ids in id_list
+ * @op: a mask of KGSL_GPUMEM_CACHE_* values
+ *
+ * Sync the cache for memory headed to and from the GPU. Certain
+ * optimizations can be made on the cache operation based on the total
+ * size of the working set of memory to be managed.
+ */
+struct kgsl_gpumem_sync_cache_bulk {
+ unsigned int *id_list;
+ unsigned int count;
+ unsigned int op;
+/* private: reserved for future use */
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
+ _IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index f14cc52..2c1fa11 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -20,6 +20,7 @@
int32_t limit_temp_degC;
int32_t temp_hysteresis_degC;
uint32_t freq_step;
+ uint32_t freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
uint32_t core_control_mask;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f551e75..6d7d178 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -3069,4 +3069,32 @@
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
};
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ * handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
+ */
+enum nl80211_connect_failed_reason {
+ NL80211_CONN_FAIL_MAX_CLIENTS,
+ NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ * listed in ACL, i.e. allow all the stations which are not listed
+ * in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ * in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
index 0943dda..eb20e80 100644
--- a/include/linux/of_coresight.h
+++ b/include/linux/of_coresight.h
@@ -13,7 +13,7 @@
#ifndef __LINUX_OF_CORESIGHT_H
#define __LINUX_OF_CORESIGHT_H
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_CORESIGHT
extern struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node);
extern struct coresight_cti_data *of_get_coresight_cti_data(
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 6394988..5e87259 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -15,12 +15,38 @@
#include <linux/errno.h>
+/**
+ * enum pon_trigger_source: List of PON trigger sources
+ * %PON_SMPL: PON triggered by SMPL - Sudden Momentary Power Loss
+ * %PON_RTC: PON triggered by RTC alarm
+ * %PON_DC_CHG: PON triggered by insertion of DC charger
+ * %PON_USB_CHG: PON triggered by insertion of USB
+ * %PON_PON1: PON triggered by other PMIC (multi-PMIC option)
+ * %PON_CBLPWR_N: PON triggered by power-cable insertion
+ * %PON_KPDPWR_N: PON triggered by long press of the power-key
+ */
+enum pon_trigger_source {
+ PON_SMPL = 1,
+ PON_RTC,
+ PON_DC_CHG,
+ PON_USB_CHG,
+ PON_PON1,
+ PON_CBLPWR_N,
+ PON_KPDPWR_N,
+};
+
#ifdef CONFIG_QPNP_POWER_ON
int qpnp_pon_system_pwr_off(bool reset);
int qpnp_pon_is_warm_reset(void);
+int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable);
#else
static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
static inline int qpnp_pon_is_warm_reset(void) { return -ENODEV; }
+static inline int qpnp_pon_trigger_config(enum pon_trigger_source pon_src,
+ bool enable)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 92a89f0..c2d9c17 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -118,7 +118,7 @@
#define SD_MC_INIT (struct sched_domain) { \
.min_interval = 1, \
.max_interval = 4, \
- .busy_factor = 64, \
+ .busy_factor = 1, \
.imbalance_pct = 125, \
.cache_nice_tries = 1, \
.busy_idx = 2, \
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4ae3b79..f9729c4 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -424,6 +424,8 @@
bool pool_64_bit_align;
bool enable_hbm;
bool disable_park_mode;
+ bool consider_ipa_handshake;
+ bool ahb_async_bridge_bypass;
};
struct msm_usb_host_platform_data {
@@ -465,8 +467,16 @@
};
#ifdef CONFIG_USB_BAM
bool msm_bam_lpm_ok(void);
+void msm_bam_set_hsic_host_dev(struct device *dev);
+void msm_bam_wait_for_hsic_prod_granted(void);
+bool msm_bam_hsic_lpm_ok(void);
+void msm_bam_hsic_notify_on_resume(void);
#else
static inline bool msm_bam_lpm_ok(void) { return true; }
+static inline void msm_bam_set_hsic_host_dev(struct device *dev) {}
+static inline void msm_bam_wait_for_hsic_prod_granted(void) {}
+static inline bool msm_bam_hsic_lpm_ok(void) { return true; }
+static inline void msm_bam_hsic_notify_on_resume(void) {}
#endif
#ifdef CONFIG_USB_CI13XXX_MSM
void msm_hw_bam_disable(bool bam_disable);
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index da56df6..2a53114 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -67,6 +67,8 @@
void wcnss_riva_log_debug_regs(void);
void wcnss_pronto_log_debug_regs(void);
int wcnss_device_ready(void);
+void wcnss_riva_dump_pmic_regs(void);
+int wcnss_xo_auto_detect_enabled(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index aead2d2..6cd4995 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -112,9 +112,10 @@
struct timeval in_time, out_time;
void *cookie;
int32_t *status;
-
+ int32_t duplicate_output;
+ uint32_t duplicate_identity;
struct msm_cpp_buffer_info_t input_buffer_info;
- struct msm_cpp_buffer_info_t output_buffer_info;
+ struct msm_cpp_buffer_info_t output_buffer_info[2];
};
struct cpp_hw_info {
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index 881b851..fea09dd 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -18,6 +18,7 @@
#define BYTES_PER_BLOCK (3)
#define MAX_PS_LENGTH (96)
#define MAX_RT_LENGTH (64)
+#define RX_STATIONS0_LEN (15)
#define XFRDAT0 (0x20)
#define XFRDAT1 (0x21)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dc29eb9..fb2b57a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -416,6 +416,26 @@
size_t probe_resp_len;
};
+struct mac_address {
+ u8 addr[ETH_ALEN];
+};
+
+/**
+ * struct cfg80211_acl_data - Access control list data
+ *
+ * @acl_policy: ACL policy to be applied on the station's
+ * entry specified by mac_addr
+ * @n_acl_entries: Number of MAC address entries passed
+ * @mac_addrs: List of MAC addresses of stations to be used for ACL
+ */
+struct cfg80211_acl_data {
+ enum nl80211_acl_policy acl_policy;
+ int n_acl_entries;
+
+ /* Keep it last */
+ struct mac_address mac_addrs[];
+};
+
/**
* struct cfg80211_ap_settings - AP configuration
*
@@ -432,6 +452,8 @@
* @privacy: the BSS uses privacy
* @auth_type: Authentication type (algorithm)
* @inactivity_timeout: time in seconds to determine station's inactivity.
+ * @acl: ACL configuration used by the drivers which has support for
+ * MAC address based access control
*/
struct cfg80211_ap_settings {
struct cfg80211_beacon_data beacon;
@@ -444,6 +466,7 @@
bool privacy;
enum nl80211_auth_type auth_type;
int inactivity_timeout;
+ const struct cfg80211_acl_data *acl;
};
/**
@@ -1559,6 +1582,13 @@
* later passes to cfg80211_probe_status().
*
* @set_noack_map: Set the NoAck Map for the TIDs.
+ * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
+ * Parameters include ACL policy, an array of MAC address of stations
+ * and the number of MAC addresses. If there is already a list in driver
+ * this new list replaces the existing one. Driver has to clear its ACL
+ * when number of MAC addresses entries is passed as 0. Drivers which
+ * advertise the support for MAC based ACL have to implement this callback.
+ *
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1757,6 +1787,9 @@
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie);
+
+ int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_acl_data *params);
};
/*
@@ -1924,10 +1957,6 @@
bool beacon_int_infra_match;
};
-struct mac_address {
- u8 addr[ETH_ALEN];
-};
-
struct ieee80211_txrx_stypes {
u16 tx, rx;
};
@@ -2068,6 +2097,9 @@
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
* @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
* If null, then none can be over-ridden.
+ *
+ * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
+ * supports for ACL.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2089,6 +2121,8 @@
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes;
+ u16 max_acl_mac_addrs;
+
u32 flags, features;
u32 ap_sme_capa;
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index edadaa9..60847b0 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -12,3 +12,4 @@
header-y += compress_params.h
header-y += compress_offload.h
header-y += lsm_params.h
+header-y += voice_params.h
diff --git a/include/sound/voice_params.h b/include/sound/voice_params.h
new file mode 100644
index 0000000..43e3b9d
--- /dev/null
+++ b/include/sound/voice_params.h
@@ -0,0 +1,14 @@
+#ifndef __VOICE_PARAMS_H__
+#define __VOICE_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+enum voice_lch_mode {
+ VOICE_LCH_START = 1,
+ VOICE_LCH_STOP
+};
+
+#define SNDRV_VOICE_IOCTL_LCH _IOW('U', 0x00, enum voice_lch_mode)
+
+#endif
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index f8317df..8f32475 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1604,7 +1604,6 @@
struct task_struct *next_task;
struct rq *lowest_rq;
int ret = 0;
- bool moved = false;
if (!rq->rt.overloaded)
return 0;
@@ -1674,7 +1673,6 @@
deactivate_task(rq, next_task, 0);
set_task_cpu(next_task, lowest_rq->cpu);
- moved = true;
activate_task(lowest_rq, next_task, 0);
ret = 1;
@@ -1685,11 +1683,6 @@
out:
put_task_struct(next_task);
- if (moved && task_notify_on_migrate(next_task))
- atomic_notifier_call_chain(&migration_notifier_head,
- cpu_of(lowest_rq),
- (void *)cpu_of(rq));
-
return ret;
}
@@ -1703,10 +1696,8 @@
static int pull_rt_task(struct rq *this_rq)
{
int this_cpu = this_rq->cpu, ret = 0, cpu;
- struct task_struct *p = NULL;
+ struct task_struct *p;
struct rq *src_rq;
- bool moved = false;
- int src_cpu = 0;
if (likely(!rt_overloaded(this_rq)))
return 0;
@@ -1767,10 +1758,6 @@
deactivate_task(src_rq, p, 0);
set_task_cpu(p, this_cpu);
activate_task(this_rq, p, 0);
-
- moved = true;
- src_cpu = cpu_of(src_rq);
-
/*
* We continue with the search, just in
* case there's an even higher prio task
@@ -1782,11 +1769,6 @@
double_unlock_balance(this_rq, src_rq);
}
- if (moved && task_notify_on_migrate(p))
- atomic_notifier_call_chain(&migration_notifier_head,
- this_cpu,
- (void *)src_cpu);
-
return ret;
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 798c750..8a93508 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1661,6 +1661,7 @@
long min = mark;
long lowmem_reserve = z->lowmem_reserve[classzone_idx];
int o;
+ long free_cma = 0;
free_pages -= (1 << order) - 1;
if (alloc_flags & ALLOC_HIGH)
@@ -1670,9 +1671,10 @@
#ifdef CONFIG_CMA
/* If allocation can't use CMA areas don't use free CMA pages */
if (!(alloc_flags & ALLOC_CMA))
- free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES);
+ free_cma = zone_page_state(z, NR_FREE_CMA_PAGES);
#endif
- if (free_pages <= min + lowmem_reserve)
+
+ if (free_pages - free_cma <= min + lowmem_reserve)
return false;
for (o = 0; o < order; o++) {
/* At the next order, this order's pages become unavailable */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ccdfed8..674c1fa 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -505,6 +505,11 @@
ETH_ALEN)))
return -EINVAL;
+ if (WARN_ON(wiphy->max_acl_mac_addrs &&
+ (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
+ !rdev->ops->set_mac_acl)))
+ return -EINVAL;
+
if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e1fa62e..6ed6d3e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -210,6 +210,8 @@
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
+ [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
+ [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
[NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
@@ -1066,6 +1068,11 @@
sizeof(*dev->wiphy.ht_capa_mod_mask),
dev->wiphy.ht_capa_mod_mask);
+ if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+ dev->wiphy.max_acl_mac_addrs)
+ NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
+ dev->wiphy.max_acl_mac_addrs);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -2105,6 +2112,97 @@
return err;
}
+/* This function returns an error or the number of nested attributes */
+static int validate_acl_mac_addrs(struct nlattr *nl_attr)
+{
+ struct nlattr *attr;
+ int n_entries = 0, tmp;
+
+ nla_for_each_nested(attr, nl_attr, tmp) {
+ if (nla_len(attr) != ETH_ALEN)
+ return -EINVAL;
+
+ n_entries++;
+ }
+
+ return n_entries;
+}
+
+/*
+ * This function parses ACL information and allocates memory for ACL data.
+ * On successful return, the calling function is responsible to free the
+ * ACL buffer returned by this function.
+ */
+static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
+ struct genl_info *info)
+{
+ enum nl80211_acl_policy acl_policy;
+ struct nlattr *attr;
+ struct cfg80211_acl_data *acl;
+ int i = 0, n_entries, tmp;
+
+ if (!wiphy->max_acl_mac_addrs)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (!info->attrs[NL80211_ATTR_ACL_POLICY])
+ return ERR_PTR(-EINVAL);
+
+ acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
+ if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
+ acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
+ return ERR_PTR(-EINVAL);
+
+ if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
+ return ERR_PTR(-EINVAL);
+
+ n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
+ if (n_entries < 0)
+ return ERR_PTR(n_entries);
+
+ if (n_entries > wiphy->max_acl_mac_addrs)
+ return ERR_PTR(-ENOTSUPP);
+
+ acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
+ GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
+ memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
+ i++;
+ }
+
+ acl->n_acl_entries = n_entries;
+ acl->acl_policy = acl_policy;
+
+ return acl;
+}
+
+static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct cfg80211_acl_data *acl;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!dev->ieee80211_ptr->beacon_interval)
+ return -EINVAL;
+
+ acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ err = rdev->ops->set_mac_acl(&rdev->wiphy, dev, acl);
+
+ kfree(acl);
+
+ return err;
+}
+
static int nl80211_parse_beacon(struct genl_info *info,
struct cfg80211_beacon_data *bcn)
{
@@ -2251,9 +2349,18 @@
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
}
+ if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
+ params.acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(params.acl))
+ return PTR_ERR(params.acl);
+ }
+
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
if (!err)
wdev->beacon_interval = params.beacon_interval;
+
+ kfree(params.acl);
+
return err;
}
@@ -7063,6 +7170,14 @@
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_SET_MAC_ACL,
+ .doit = nl80211_set_mac_acl,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_UPDATE_FT_IES,
.doit = nl80211_update_ft_ies,
.policy = nl80211_policy,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 155585a..8d6dee3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -456,4 +456,8 @@
tristate
config SND_SOC_MSM_HDMI_CODEC_RX
- tristate
+ bool "HDMI Audio Playback"
+ depends on FB_MSM_MDSS_HDMI_PANEL && SND_SOC_MSM8974
+ help
+ HDMI audio drivers should be built only if the platform
+ supports hdmi panel.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f0cd026..c0469e3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -104,7 +104,7 @@
snd-soc-timpani-objs := timpani.o
snd-soc-msm-stub-objs := msm_stub.o
-snd-soc-msm-hdmi-rx-objs := msm_hdmi_codec_rx.o
+obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX) := msm_hdmi_codec_rx.o
# Amp
snd-soc-max9877-objs := max9877.o
@@ -214,7 +214,6 @@
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_MSM_STUB) += snd-soc-msm-stub.o
-obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX) += snd-soc-msm-hdmi-rx.o
# Amp
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index e1a904f..1a11997 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1784,9 +1784,7 @@
} else {
snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
0x0f, 0x00);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
- 0x01, 0x01);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
0x03, 0x00);
}
return 0;
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 616f8d5..58ea22d 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -45,6 +45,7 @@
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
#define BITS_PER_REG 8
+#define SITAR_RX_PORT_START_NUMBER 10
enum {
AIF1_PB = 0,
@@ -53,11 +54,11 @@
};
struct wcd9xxx_ch sitar_rx_chs[SITAR_RX_MAX] = {
- WCD9XXX_CH(10, 0),
- WCD9XXX_CH(11, 1),
- WCD9XXX_CH(12, 2),
- WCD9XXX_CH(13, 3),
- WCD9XXX_CH(14, 4)
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 4, 4)
};
struct wcd9xxx_ch sitar_tx_chs[SITAR_TX_MAX] = {
@@ -1368,10 +1369,10 @@
vport_check_table[dai_id],
port_id,
sitar_p->dai)) {
- pr_info("%s: TX%u is used by other virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -1381,10 +1382,10 @@
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- pr_info("%s: TX%u port is used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
__func__, port_id + 1);
else
- pr_info("%s: TX%u port is not used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
mutex_unlock(&codec->mutex);
@@ -1446,9 +1447,13 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ SITAR_RX_PORT_START_NUMBER,
+ &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
@@ -1458,14 +1463,10 @@
goto err;
}
-
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
-
mutex_unlock(&codec->mutex);
return 0;
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
err:
mutex_unlock(&codec->mutex);
return -EINVAL;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index b71dd65..b31f7cc 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -60,6 +60,7 @@
#define BITS_PER_REG 8
/* This actual number of TX ports supported in slimbus slave */
#define TAPAN_TX_PORT_NUMBER 16
+#define TAPAN_RX_PORT_START_NUMBER 16
/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
#define TAPAN_SLIM_CODEC_TX_PORTS 5
@@ -155,11 +156,11 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
static const struct wcd9xxx_ch tapan_rx_chs[TAPAN_RX_MAX] = {
- WCD9XXX_CH(16, 0),
- WCD9XXX_CH(17, 1),
- WCD9XXX_CH(18, 2),
- WCD9XXX_CH(19, 3),
- WCD9XXX_CH(20, 4),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 4, 4),
};
static const struct wcd9xxx_ch tapan_tx_chs[TAPAN_TX_MAX] = {
@@ -1410,7 +1411,7 @@
dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -1495,23 +1496,35 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAPAN_RX_PORT_START_NUMBER,
+ &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tapan_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
case 2:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAPAN_RX_PORT_START_NUMBER,
+ &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
break;
case 3:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAPAN_RX_PORT_START_NUMBER,
+ &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
break;
@@ -1520,13 +1533,10 @@
goto err;
}
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
-
mutex_unlock(&codec->mutex);
return 0;
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
err:
mutex_unlock(&codec->mutex);
return -EINVAL;
@@ -4261,9 +4271,6 @@
*/
TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
- /* not needed if MBHC is not needed */
- /* Disable TX7 internal biasing path which can cause leakage */
- TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
};
static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 29703b9..69e4cca 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -129,6 +129,8 @@
#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
+#define TABLA_RX_PORT_START_NUMBER 10
+
#define TABLA_ACQUIRE_LOCK(x) do { \
mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
@@ -302,13 +304,13 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
static const struct wcd9xxx_ch tabla_rx_chs[TABLA_RX_MAX] = {
- WCD9XXX_CH(10, 0),
- WCD9XXX_CH(11, 1),
- WCD9XXX_CH(12, 2),
- WCD9XXX_CH(13, 3),
- WCD9XXX_CH(14, 4),
- WCD9XXX_CH(15, 5),
- WCD9XXX_CH(16, 6)
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 4, 4),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 5, 5),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 6, 6)
};
static const struct wcd9xxx_ch tabla_tx_chs[TABLA_TX_MAX] = {
@@ -2031,10 +2033,10 @@
vtable,
port_id,
tabla_p->dai)) {
- pr_info("%s: TX%u is used by other virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -2045,10 +2047,10 @@
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- pr_info("%s: TX%u port is used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
__func__, port_id + 1);
else
- pr_info("%s: TX%u port is not used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
mutex_unlock(&codec->mutex);
@@ -2116,23 +2118,35 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TABLA_RX_PORT_START_NUMBER,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tabla_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
case 2:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TABLA_RX_PORT_START_NUMBER,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tabla_p->dai[AIF2_PB].wcd9xxx_ch_list);
break;
case 3:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TABLA_RX_PORT_START_NUMBER,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tabla_p->dai[AIF3_PB].wcd9xxx_ch_list);
break;
@@ -2140,15 +2154,8 @@
pr_err("Unknown AIF %d\n", widget->value);
goto err;
}
-
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
-
- mutex_unlock(&codec->mutex);
- return 0;
-
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
mutex_unlock(&codec->mutex);
return 0;
err:
@@ -2703,7 +2710,7 @@
}
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
- msleep(250);
+ msleep(20);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
pr_debug("%s: leave\n", __func__);
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
index 0885c09..e834b80 100644
--- a/sound/soc/codecs/wcd9320-tables.c
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -671,6 +671,16 @@
[TAIKO_A_CDC_MAD_BEACON_CTL_8] = 1,
[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR] = 1,
[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL0] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL1] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL2] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL3] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL4] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL5] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL6] = 1,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL7] = 1,
+
};
const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE] = {
@@ -1356,4 +1366,14 @@
TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR,
[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] =
TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL] =
+ TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL0] = TAIKO_A_CDC_SPKR_CLIPDET_VAL0__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL1] = TAIKO_A_CDC_SPKR_CLIPDET_VAL1__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL2] = TAIKO_A_CDC_SPKR_CLIPDET_VAL2__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL3] = TAIKO_A_CDC_SPKR_CLIPDET_VAL3__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL4] = TAIKO_A_CDC_SPKR_CLIPDET_VAL4__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL5] = TAIKO_A_CDC_SPKR_CLIPDET_VAL5__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL6] = TAIKO_A_CDC_SPKR_CLIPDET_VAL6__POR,
+ [TAIKO_A_CDC_SPKR_CLIPDET_VAL7] = TAIKO_A_CDC_SPKR_CLIPDET_VAL7__POR,
};
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 5d4f9e6..ab96baf 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -41,6 +41,8 @@
#define TAIKO_MAD_SLIMBUS_TX_PORT 12
#define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+#define TAIKO_VALIDATE_RX_SBPORT_RANGE(port) ((port >= 16) && (port <= 22))
+#define TAIKO_CONVERT_RX_SBPORT_ID(port) (port - 16) /* RX1 port ID = 0 */
#define TAIKO_HPH_PA_SETTLE_COMP_ON 3000
#define TAIKO_HPH_PA_SETTLE_COMP_OFF 13000
@@ -294,6 +296,7 @@
#define NUM_INTERPOLATORS 7
#define BITS_PER_REG 8
#define TAIKO_TX_PORT_NUMBER 16
+#define TAIKO_RX_PORT_START_NUMBER 16
#define TAIKO_I2S_MASTER_MODE_MASK 0x08
@@ -409,19 +412,19 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
static const struct wcd9xxx_ch taiko_rx_chs[TAIKO_RX_MAX] = {
- WCD9XXX_CH(16, 0),
- WCD9XXX_CH(17, 1),
- WCD9XXX_CH(18, 2),
- WCD9XXX_CH(19, 3),
- WCD9XXX_CH(20, 4),
- WCD9XXX_CH(21, 5),
- WCD9XXX_CH(22, 6),
- WCD9XXX_CH(23, 7),
- WCD9XXX_CH(24, 8),
- WCD9XXX_CH(25, 9),
- WCD9XXX_CH(26, 10),
- WCD9XXX_CH(27, 11),
- WCD9XXX_CH(28, 12),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 4, 4),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 5, 5),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 6, 6),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 7, 7),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 8, 8),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 9, 9),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 10, 10),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 11, 11),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 12, 12),
};
static const struct wcd9xxx_ch taiko_tx_chs[TAIKO_TX_MAX] = {
@@ -2042,11 +2045,10 @@
vtable,
port_id,
taiko_p->dai)) {
- pr_debug("%s: TX%u is used by other\n"
- "virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -2057,11 +2059,11 @@
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- pr_debug("%s: TX%u port is used by\n"
+ dev_dbg(codec->dev, "%s: TX%u port is used by\n"
"this virtual port\n",
__func__, port_id + 1);
else
- pr_debug("%s: TX%u port is not used by\n"
+ dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
"this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
@@ -2130,23 +2132,35 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &taiko_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAIKO_RX_PORT_START_NUMBER,
+ &taiko_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&taiko_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
case 2:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &taiko_p->dai[AIF2_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAIKO_RX_PORT_START_NUMBER,
+ &taiko_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&taiko_p->dai[AIF2_PB].wcd9xxx_ch_list);
break;
case 3:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &taiko_p->dai[AIF3_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAIKO_RX_PORT_START_NUMBER,
+ &taiko_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&taiko_p->dai[AIF3_PB].wcd9xxx_ch_list);
break;
@@ -2154,14 +2168,11 @@
pr_err("Unknown AIF %d\n", widget->value);
goto err;
}
-
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
mutex_unlock(&codec->mutex);
return 0;
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
err:
mutex_unlock(&codec->mutex);
return -EINVAL;
@@ -3097,7 +3108,7 @@
}
release_firmware(fw);
break;
- case SND_SOC_DAPM_POST_PMD:
+ case SND_SOC_DAPM_PRE_PMD:
msleep(40);
snd_soc_update_bits(codec, TAIKO_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
snd_soc_update_bits(codec, TAIKO_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
@@ -3198,8 +3209,6 @@
snd_soc_update_bits(codec,
TAIKO_A_RX_HPH_CNP_EN, 0x30, 0x00);
msleep(40);
- }
- if (w->shift == 5) {
snd_soc_update_bits(codec,
TAIKO_A_TX_7_MBHC_EN, 0x80, 00);
ret |= taiko_codec_enable_anc(w, kcontrol, event);
@@ -4266,6 +4275,65 @@
return 0;
}
+static void taiko_set_rxsb_port_format(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx_codec_dai_data *cdc_dai;
+ struct wcd9xxx_ch *ch;
+ int port;
+ u8 bit_sel;
+ u16 sb_ctl_reg, field_shift;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bit_sel = 0x2;
+ taiko_p->dai[dai->id].bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_sel = 0x0;
+ taiko_p->dai[dai->id].bit_width = 24;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid format\n");
+ return;
+ }
+
+ cdc_dai = &taiko_p->dai[dai->id];
+
+ list_for_each_entry(ch, &cdc_dai->wcd9xxx_ch_list, list) {
+ port = wcd9xxx_get_slave_port(ch->ch_num);
+
+ if (IS_ERR_VALUE(port) ||
+ !TAIKO_VALIDATE_RX_SBPORT_RANGE(port)) {
+ dev_warn(codec->dev,
+ "%s: invalid port ID %d returned for RX DAI\n",
+ __func__, port);
+ return;
+ }
+
+ port = TAIKO_CONVERT_RX_SBPORT_ID(port);
+
+ if (port <= 3) {
+ sb_ctl_reg = TAIKO_A_CDC_CONN_RX_SB_B1_CTL;
+ field_shift = port << 1;
+ } else if (port <= 6) {
+ sb_ctl_reg = TAIKO_A_CDC_CONN_RX_SB_B2_CTL;
+ field_shift = (port - 4) << 1;
+ } else { /* should not happen */
+ dev_warn(codec->dev,
+ "%s: bad port ID %d\n", __func__, port);
+ return;
+ }
+
+ dev_dbg(codec->dev, "%s: sb_ctl_reg %x field_shift %x\n",
+ __func__, sb_ctl_reg, field_shift);
+ snd_soc_update_bits(codec, sb_ctl_reg, 0x3 << field_shift,
+ bit_sel << field_shift);
+ }
+}
+
static int taiko_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -4380,29 +4448,7 @@
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
} else {
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
- 0xFF, 0xAA);
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
- 0xFF, 0x2A);
- taiko->dai[dai->id].bit_width = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
- 0xFF, 0x00);
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
- 0xFF, 0x00);
- taiko->dai[dai->id].bit_width = 24;
- break;
- default:
- dev_err(codec->dev, "Invalid format\n");
- break;
- }
+ taiko_set_rxsb_port_format(params, dai);
taiko->dai[dai->id].rate = params_rate(params);
}
break;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a67fcad..d246e17 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1556,6 +1556,9 @@
wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
wcd9xxx_schedule_hs_detect_plug(mbhc,
&mbhc->correct_plug_swch);
+ } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ wcd9xxx_schedule_hs_detect_plug(mbhc,
+ &mbhc->correct_plug_swch);
} else {
pr_debug("%s: Valid plug found, determine plug type %d\n",
__func__, plug_type);
@@ -2156,6 +2159,9 @@
wcd9xxx_report_plug(mbhc, 1,
SND_JACK_HEADPHONE);
}
+ } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ pr_debug("%s: High HPH detected, continue polling\n",
+ __func__);
} else {
if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
pt_gnd_mic_swap_cnt++;
@@ -2194,6 +2200,11 @@
}
}
+ if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
+ __func__);
+ wcd9xxx_find_plug_and_report(mbhc, plug_type);
+ }
/* Turn off override */
if (!correction)
wcd9xxx_turn_onoff_override(codec, false);
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 66c475f..7fd62f1 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -180,7 +180,6 @@
select SND_SOC_MSM_STUB
select SND_SOC_MSM_HOSTLESS_PCM
select SND_SOC_WCD9320
- select SND_SOC_MSM_HDMI_CODEC_RX
select SND_DYNAMIC_MINORS
select AUDIO_OCMEM
select DOLBY_DAP
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index e54f8b7..373090e 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -1302,7 +1302,7 @@
}
rc = wait_event_timeout(the_locks.flush_wait,
prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
+ if (!rc)
pr_err("Flush cmd timeout\n");
prtd->pcm_irq_pos = 0;
}
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index d5281e4..28e112c 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -434,7 +434,7 @@
__func__, atomic_read(&prtd->out_count));
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
@@ -487,7 +487,7 @@
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (ret < 0)
+ if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -525,7 +525,7 @@
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 26bf3d9..d620099 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -537,7 +537,7 @@
__func__, atomic_read(&prtd->out_count));
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
@@ -590,7 +590,7 @@
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (ret < 0)
+ if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -629,7 +629,7 @@
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 95c5cd7..bfab124 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -382,7 +382,7 @@
pr_debug("%s\n", __func__);
rc = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
+ if (!rc)
pr_err("EOS cmd timeout\n");
prtd->pcm_irq_pos = 0;
}
@@ -537,7 +537,7 @@
pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
rc = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
+ if (!rc)
pr_err("Flush cmd timeout\n");
prtd->pcm_irq_pos = 0;
break;
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 1d15c11..c37e932 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -419,7 +419,7 @@
__func__, atomic_read(&prtd->out_count));
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
@@ -472,7 +472,7 @@
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (ret < 0)
+ if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -510,7 +510,7 @@
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 86e3d75..15eb476 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -638,7 +638,7 @@
#undef S
#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(tapan_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1650);
+ S(v_hs_max, 2450);
#undef S
#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(tapan_cal)->X) = (Y))
S(c[0], 62);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 945840d..ae92ca4 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1949,6 +1949,52 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_LSM1,
},
+ /* Multiple Tunnel instances */
+ {
+ .name = "MSM8974 Compr2",
+ .stream_name = "COMPR2",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {
+ .name = "MSM8974 Compr3",
+ .stream_name = "COMPR3",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {
+ .name = "MSM8974 Compr4",
+ .stream_name = "COMPR4",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 4db3ea5..02f6ff1 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -613,6 +613,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ {/* hw:x,13 */
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
/* Backend I2S DAI Links */
{
.name = LPASS_BE_SEC_MI2S_RX,
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 9558fa4..c4851f3 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -840,7 +840,7 @@
ret = wait_event_timeout(this_afe.wait,
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto fail_cmd;
@@ -918,7 +918,7 @@
ret = wait_event_timeout(this_afe.wait,
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto fail_cmd;
@@ -979,7 +979,7 @@
ret = wait_event_timeout(this_afe.wait,
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto fail_cmd;
@@ -1731,7 +1731,7 @@
ret = wait_event_timeout(this_afe.wait,
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto fail_cmd;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index bb13695..60f4669 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -1058,7 +1058,9 @@
}
/* Set encoder properties. */
switch (common.mvs_info.media_type) {
- case VSS_MEDIA_ID_EVRC_MODEM: {
+ case VSS_MEDIA_ID_EVRC_MODEM:
+ case VSS_MEDIA_ID_4GV_NB_MODEM:
+ case VSS_MEDIA_ID_4GV_WB_MODEM: {
struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
pr_debug("Setting EVRC min-max rate\n");
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index a2e0b87..3b6a415 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -1010,10 +1010,11 @@
case AUDIO_GET_SPEAKER_PROT:
mutex_lock(&acdb_data.acdb_mutex);
/*Indicates calibration was succesfull*/
- if (!acdb_data.spk_prot_cfg.mode) {
+ if (acdb_data.spk_prot_cfg.mode == MSM_SPKR_PROT_CALIBRATED) {
prot_status.r0 = acdb_data.spk_prot_cfg.r0;
prot_status.status = 0;
- } else if (acdb_data.spk_prot_cfg.mode == 1) {
+ } else if (acdb_data.spk_prot_cfg.mode ==
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS) {
/*Call AFE to query the status*/
acdb_spk_status.status = -EINVAL;
acdb_spk_status.r0 = -1;
@@ -1021,7 +1022,8 @@
prot_status.r0 = acdb_spk_status.r0;
prot_status.status = acdb_spk_status.status;
if (!acdb_spk_status.status) {
- acdb_data.spk_prot_cfg.mode = 0;
+ acdb_data.spk_prot_cfg.mode =
+ MSM_SPKR_PROT_CALIBRATED;
acdb_data.spk_prot_cfg.r0 = prot_status.r0;
}
} else {
@@ -1206,7 +1208,7 @@
{
memset(&acdb_data, 0, sizeof(acdb_data));
/*Speaker protection disabled*/
- acdb_data.spk_prot_cfg.mode = -1;
+ acdb_data.spk_prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
mutex_init(&acdb_data.acdb_mutex);
atomic_set(&usage_count, 0);
atomic_set(&acdb_data.valid_adm_custom_top, 1);
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index ec5359c..6bccdb7 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -125,7 +125,6 @@
int i = 0;
int time_stamp_flag = 0;
int buffer_length = 0;
- int stop_playback = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -150,15 +149,9 @@
/*
* check for underrun
*/
- snd_pcm_stream_lock_irq(substream);
- if (snd_pcm_playback_empty(substream)) {
+ if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+ pr_err("render stopped");
runtime->render_flag |= SNDRV_RENDER_STOPPED;
- stop_playback = 1;
- }
- snd_pcm_stream_unlock_irq(substream);
-
- if (stop_playback) {
- pr_err("%s empty buffer, stop writes\n", __func__);
break;
}
@@ -493,11 +486,6 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req,
- 0, 1))
- audio_ocmem_process_req(AUDIO, true);
- }
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
switch (compr->info.codec_param.codec.id) {
@@ -619,19 +607,33 @@
populate_codec_list(compr, runtime);
runtime->private_data = compr;
atomic_set(&prtd->eos, 0);
- atomic_set(&compressed_audio.audio_ocmem_req, 0);
compressed_audio.prtd = &compr->prtd;
-
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 0, 1))
+ audio_ocmem_process_req(AUDIO, true);
+ else
+ atomic_inc(&compressed_audio.audio_ocmem_req);
+ pr_debug("%s: req: %d\n", __func__,
+ atomic_read(&compressed_audio.audio_ocmem_req));
+ }
return 0;
}
int compressed_set_volume(unsigned volume)
{
int rc = 0;
+ int avg_vol = 0;
if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
- rc = q6asm_set_lrgain(compressed_audio.prtd->audio_client,
- (volume >> 16) & 0xFFFF,
- volume & 0xFFFF);
+ if (compressed_audio.prtd->channel_mode > 2) {
+ avg_vol = (((volume >> 16) & 0xFFFF) +
+ (volume & 0xFFFF)) / 2;
+ rc = q6asm_set_volume(
+ compressed_audio.prtd->audio_client, avg_vol);
+ } else {
+ rc = q6asm_set_lrgain(
+ compressed_audio.prtd->audio_client,
+ (volume >> 16) & 0xFFFF, volume & 0xFFFF);
+ }
if (rc < 0) {
pr_err("%s: Send Volume command failed rc=%d\n",
__func__, rc);
@@ -653,8 +655,14 @@
dir = IN;
atomic_set(&prtd->pending_buffer, 0);
- if (atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 1, 0))
+
+ if (atomic_read(&compressed_audio.audio_ocmem_req) > 1)
+ atomic_dec(&compressed_audio.audio_ocmem_req);
+ else if (atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 1, 0))
audio_ocmem_process_req(AUDIO, false);
+
+ pr_debug("%s: req: %d\n", __func__,
+ atomic_read(&compressed_audio.audio_ocmem_req));
prtd->pcm_irq_pos = 0;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
compressed_audio.prtd = NULL;
@@ -733,9 +741,17 @@
struct msm_audio *prtd = runtime->private_data;
struct audio_client *ac = prtd->audio_client;
struct audio_port_data *apd = ac->port;
- struct audio_buffer *ab = &(apd[IN].buf[0]);
+ struct audio_buffer *ab;
+ int dir = -1;
+
prtd->mmap_flag = 1;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
return msm_audio_ion_mmap(ab, vma);
}
@@ -785,6 +801,11 @@
prtd->audio_client->perf_mode,
prtd->session_id,
substream->stream);
+ /* the number of channels are required to call volume api
+ accoridngly. So, get channels from hw params */
+ if ((params_channels(params) > 0) &&
+ (params_periods(params) <= runtime->hw.channels_max))
+ prtd->channel_mode = params_channels(params);
ret = compressed_set_volume(0);
if (ret < 0)
@@ -1171,6 +1192,8 @@
dev_info(&pdev->dev, "%s: dev name %s\n",
__func__, dev_name(&pdev->dev));
+
+ atomic_set(&compressed_audio.audio_ocmem_req, 0);
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index e6934f6..9ace410 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -641,7 +641,7 @@
DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
int port_id = dolby_dap_params_states.port_id;
if (port_id == DOLBY_INVALID_PORT_ID) {
- pr_err("%s, port_id not set, returning error", __func__);
+ pr_debug("%s, port_id not set, returning error", __func__);
ucontrol->value.integer.value[0] = 0;
return -EINVAL;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 2a64ae2..c4b44fe 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
#include <sound/core.h>
#include <sound/soc.h>
@@ -517,21 +518,21 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pcm_afe_info *prtd = runtime->private_data;
- int result = 0;
+ struct afe_audio_client *ac = prtd->audio_client;
+ struct afe_audio_port_data *apd = ac->port;
+ struct afe_audio_buffer *ab;
+ int dir = -1;
pr_debug("%s\n", __func__);
prtd->mmap_flag = 1;
- if (runtime->dma_addr && runtime->dma_bytes) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- result = remap_pfn_range(vma, vma->vm_start,
- runtime->dma_addr >> PAGE_SHIFT,
- runtime->dma_bytes,
- vma->vm_page_prot);
- } else {
- pr_err("Physical address or size of buf is NULL");
- return -EINVAL;
- }
- return result;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
+ return msm_audio_ion_mmap((struct audio_buffer *)ab, vma);
}
static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 7055c57..9899f97 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -427,9 +427,17 @@
struct msm_audio *prtd = runtime->private_data;
struct audio_client *ac = prtd->audio_client;
struct audio_port_data *apd = ac->port;
- struct audio_buffer *ab = &(apd[IN].buf[0]);
+ struct audio_buffer *ab;
+ int dir = -1;
+
prtd->mmap_flag = 1;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
return msm_audio_ion_mmap(ab, vma);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index f4ca5b8..0592d10 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -633,9 +633,17 @@
struct msm_audio *prtd = runtime->private_data;
struct audio_client *ac = prtd->audio_client;
struct audio_port_data *apd = ac->port;
- struct audio_buffer *ab = &(apd[IN].buf[0]);
+ struct audio_buffer *ab;
+ int dir = -1;
+
prtd->mmap_flag = 1;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ab = &(apd[dir].buf[0]);
+
return msm_audio_ion_mmap(ab, vma);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 643f280..d7148f1 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -257,6 +257,12 @@
{INVALID_SESSION, INVALID_SESSION},
/* MULTIMEDIA5 */
{INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA6 */
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA7 */
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA8 */
+ {INVALID_SESSION, INVALID_SESSION},
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -379,6 +385,10 @@
else if (msm_bedais[i].format ==
SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
+
+ if (msm_bedais[i].port_id == VOICE_RECORD_RX ||
+ msm_bedais[i].port_id == VOICE_RECORD_TX)
+ topology = DEFAULT_COPP_TOPOLOGY;
if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
(channels > 0))
adm_multi_ch_copp_open(msm_bedais[i].port_id,
@@ -400,7 +410,8 @@
msm_bedais[i].port_id;
port_id = srs_port_id = msm_bedais[i].port_id;
srs_send_params(srs_port_id, 1, 0);
- if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+ if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+ (!perf_mode))
if (dolby_dap_init(port_id,
msm_bedais[i].channel) < 0)
pr_err("%s: Err init dolby dap\n",
@@ -443,7 +454,8 @@
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
adm_close(msm_bedais[i].port_id,
test_bit(fedai_id, &msm_bedais[i].perf_mode));
- if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+ if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+ (!test_bit(fedai_id, &msm_bedais[i].perf_mode)))
dolby_dap_deinit(msm_bedais[i].port_id);
}
}
@@ -508,6 +520,10 @@
if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
+ if (msm_bedais[reg].port_id == VOICE_RECORD_RX ||
+ msm_bedais[reg].port_id == VOICE_RECORD_TX)
+ topology = DEFAULT_COPP_TOPOLOGY;
+
if ((session_type == SESSION_TYPE_RX) &&
(channels > 0)) {
perf_mode = test_bit(val,
@@ -530,7 +546,8 @@
perf_mode);
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
- if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+ if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+ (!perf_mode))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
@@ -544,7 +561,8 @@
INVALID_SESSION) {
perf_mode = test_bit(val, &msm_bedais[reg].perf_mode);
adm_close(msm_bedais[reg].port_id, perf_mode);
- if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+ if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+ (!perf_mode))
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
fe_dai_map[val][session_type], path_type,
@@ -1345,6 +1363,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -1363,6 +1390,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1381,6 +1417,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -1399,6 +1444,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -1417,6 +1471,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
@@ -1450,6 +1513,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
@@ -1477,6 +1549,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1495,6 +1576,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
/* incall music delivery mixer */
static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1531,6 +1621,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1549,6 +1648,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1567,6 +1675,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1585,6 +1702,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1603,6 +1729,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -2555,6 +2690,9 @@
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
@@ -2855,6 +2993,9 @@
{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"PRI_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2862,6 +3003,9 @@
{"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SEC_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2869,6 +3013,9 @@
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
@@ -2876,6 +3023,9 @@
{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
{"HDMI Mixer", "MultiMedia5", "MM_DL5"},
+ {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
+ {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
+ {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
{"HDMI", NULL, "HDMI Mixer"},
/* incall */
@@ -2896,6 +3046,9 @@
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2948,6 +3101,9 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2955,6 +3111,9 @@
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2962,6 +3121,9 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
@@ -2982,6 +3144,9 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2989,6 +3154,9 @@
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3287,9 +3455,10 @@
adm_close(bedai->port_id,
test_bit(i, &(bedai->perf_mode)));
srs_port_id = -1;
- clear_bit(i, &(bedai->perf_mode));
- if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+ if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+ (!test_bit(i, &(bedai->perf_mode))))
dolby_dap_deinit(bedai->port_id);
+ clear_bit(i, &(bedai->perf_mode));
}
}
@@ -3348,6 +3517,10 @@
if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
+ if (bedai->port_id == VOICE_RECORD_RX ||
+ bedai->port_id == VOICE_RECORD_TX)
+ topology = DEFAULT_COPP_TOPOLOGY;
+
if ((playback) && (channels > 0)) {
perf_mode = test_bit(i, &(bedai->perf_mode));
adm_multi_ch_copp_open(bedai->port_id,
@@ -3371,7 +3544,8 @@
perf_mode);
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
- if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+ if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+ (!perf_mode))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4a58369..9750756 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -67,6 +67,9 @@
MSM_FRONTEND_DAI_MULTIMEDIA3,
MSM_FRONTEND_DAI_MULTIMEDIA4,
MSM_FRONTEND_DAI_MULTIMEDIA5,
+ MSM_FRONTEND_DAI_MULTIMEDIA6,
+ MSM_FRONTEND_DAI_MULTIMEDIA7,
+ MSM_FRONTEND_DAI_MULTIMEDIA8,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
@@ -79,8 +82,8 @@
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA5 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA5
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA8 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA8
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 25bb72f..5485440 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -281,6 +281,58 @@
return ret;
}
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_voice *prtd = runtime->private_data;
+ uint16_t session_id = get_session_id(prtd);
+ enum voice_lch_mode lch_mode;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_VOICE_IOCTL_LCH:
+ if (copy_from_user(&lch_mode, (void *)arg,
+ sizeof(enum voice_lch_mode))) {
+ pr_err("%s: Copy from user failed, size %d\n", __func__,
+ sizeof(enum voice_lch_mode));
+
+ ret = -EFAULT;
+ break;
+ }
+
+ pr_debug("%s: %s lch_mode:%d\n",
+ __func__, substream->pcm->id, lch_mode);
+
+ switch (lch_mode) {
+ case VOICE_LCH_START:
+ case VOICE_LCH_STOP:
+ ret = voc_set_lch(session_id, lch_mode);
+ break;
+
+ default:
+ pr_err("%s: Invalid LCH MODE %d\n", __func__, lch_mode);
+
+ ret = -EFAULT;
+ }
+
+ break;
+ default:
+ pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+ __func__, cmd);
+
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ break;
+ }
+
+ if (!ret)
+ pr_debug("%s: ret %d\n", __func__, ret);
+ else
+ pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, ret);
+
+ return ret;
+}
+
static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -476,29 +528,6 @@
return 0;
}
-static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int wv_enable = ucontrol->value.integer.value[0];
-
- pr_debug("%s: wv enable=%d\n", __func__, wv_enable);
-
- voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
- wv_enable);
- voc_set_widevoice_enable(voc_get_session_id(VOICE2_SESSION_NAME),
- wv_enable);
-
- return 0;
-}
-
-static int msm_voice_widevoice_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- voc_get_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME));
- return 0;
-}
-
static int msm_voice_slowtalk_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -524,30 +553,6 @@
return 0;
}
-static int msm_voice_fens_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int fens_enable = ucontrol->value.integer.value[0];
-
- pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
-
- voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS, fens_enable);
- voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS, fens_enable);
-
- return 0;
-}
-
-static int msm_voice_fens_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS);
- return 0;
-}
-
static struct snd_kcontrol_new msm_voice_controls[] = {
SOC_SINGLE_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
msm_voice_rx_device_mute_get,
@@ -558,12 +563,8 @@
msm_voice_volume_get, msm_voice_volume_put),
SOC_ENUM_EXT("TTY Mode", msm_tty_mode_enum[0], msm_voice_tty_mode_get,
msm_voice_tty_mode_put),
- SOC_SINGLE_EXT("Widevoice Enable", SND_SOC_NOPM, 0, 1, 0,
- msm_voice_widevoice_get, msm_voice_widevoice_put),
SOC_SINGLE_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, 1, 0,
msm_voice_slowtalk_get, msm_voice_slowtalk_put),
- SOC_SINGLE_EXT("FENS Enable", SND_SOC_NOPM, 0, 1, 0,
- msm_voice_fens_get, msm_voice_fens_put),
SOC_SINGLE_EXT("VoLTE Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
msm_volte_rx_device_mute_get,
msm_volte_rx_device_mute_put),
@@ -581,11 +582,12 @@
};
static struct snd_pcm_ops msm_pcm_ops = {
- .open = msm_pcm_open,
- .hw_params = msm_pcm_hw_params,
- .close = msm_pcm_close,
- .prepare = msm_pcm_prepare,
- .trigger = msm_pcm_trigger,
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .ioctl = msm_pcm_ioctl,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index b5ce28f..f17fe5b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -109,10 +109,9 @@
wait_queue_head_t in_wait;
struct mutex lock;
- struct mutex in_lock;
- struct mutex out_lock;
spinlock_t dsp_lock;
+ spinlock_t dsp_ul_lock;
uint32_t mode;
uint32_t rate_type;
@@ -272,7 +271,7 @@
return;
/* Copy up-link packet into out_queue. */
- spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
/* discarding UL packets till start is received */
if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
@@ -325,10 +324,10 @@
pr_debug("ul_pkt: pkt_len =%d, frame.len=%d\n", pkt_len,
buf_node->frame.len);
prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
- spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->capture_substream);
} else {
- spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
pr_err("UL data dropped\n");
}
@@ -526,6 +525,7 @@
struct voip_buf_node *buf_node = NULL;
struct snd_pcm_runtime *runtime = substream->runtime;
struct voip_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
int count = frames_to_bytes(runtime, frames);
pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
@@ -535,12 +535,13 @@
prtd->state == VOIP_STOPPED),
1 * HZ);
if (ret > 0) {
- mutex_lock(&prtd->in_lock);
if (count <= VOIP_MAX_VOC_PKT_SIZE) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
buf_node =
list_first_entry(&prtd->free_in_queue,
struct voip_buf_node, list);
list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
if (prtd->mode == MODE_PCM) {
ret = copy_from_user(&buf_node->frame.voc_pkt,
buf, count);
@@ -548,14 +549,15 @@
} else
ret = copy_from_user(&buf_node->frame,
buf, count);
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
list_add_tail(&buf_node->list, &prtd->in_queue);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
} else {
pr_err("%s: Write cnt %d is > VOIP_MAX_VOC_PKT_SIZE\n",
__func__, count);
ret = -ENOMEM;
}
- mutex_unlock(&prtd->in_lock);
} else if (ret == 0) {
pr_err("%s: No free DL buffs\n", __func__);
ret = -ETIMEDOUT;
@@ -574,6 +576,7 @@
struct voip_buf_node *buf_node = NULL;
struct snd_pcm_runtime *runtime = substream->runtime;
struct voip_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
count = frames_to_bytes(runtime, frames);
@@ -585,12 +588,13 @@
1 * HZ);
if (ret > 0) {
- mutex_lock(&prtd->out_lock);
if (count <= VOIP_MAX_VOC_PKT_SIZE) {
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
buf_node = list_first_entry(&prtd->out_queue,
struct voip_buf_node, list);
list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
if (prtd->mode == MODE_PCM)
ret = copy_to_user(buf,
&buf_node->frame.voc_pkt,
@@ -604,15 +608,17 @@
__func__, ret);
ret = -EFAULT;
}
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
list_add_tail(&buf_node->list,
&prtd->free_out_queue);
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+
} else {
pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
__func__, count);
ret = -ENOMEM;
}
- mutex_unlock(&prtd->out_lock);
} else if (ret == 0) {
pr_err("%s: No UL data available\n", __func__);
@@ -646,6 +652,7 @@
struct snd_pcm_substream *p_substream, *c_substream;
struct snd_pcm_runtime *runtime;
struct voip_drv_info *prtd;
+ unsigned long dsp_flags;
if (substream == NULL) {
pr_err("substream is NULL\n");
@@ -684,7 +691,7 @@
goto capt;
}
if (p_dma_buf->area != NULL) {
- mutex_lock(&prtd->in_lock);
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
list_for_each_safe(ptr, next, &prtd->in_queue) {
buf_node = list_entry(ptr,
struct voip_buf_node, list);
@@ -695,11 +702,11 @@
struct voip_buf_node, list);
list_del(&buf_node->list);
}
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
dma_free_coherent(p_substream->pcm->card->dev,
runtime->hw.buffer_bytes_max, p_dma_buf->area,
p_dma_buf->addr);
p_dma_buf->area = NULL;
- mutex_unlock(&prtd->in_lock);
}
/* release out_queue and free_out_queue */
capt: c_substream = prtd->capture_substream;
@@ -713,7 +720,7 @@
goto done;
}
if (c_dma_buf->area != NULL) {
- mutex_lock(&prtd->out_lock);
+ spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
list_for_each_safe(ptr, next, &prtd->out_queue) {
buf_node = list_entry(ptr,
struct voip_buf_node, list);
@@ -724,11 +731,11 @@
struct voip_buf_node, list);
list_del(&buf_node->list);
}
+ spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
dma_free_coherent(c_substream->pcm->card->dev,
runtime->hw.buffer_bytes_max, c_dma_buf->area,
c_dma_buf->addr);
c_dma_buf->area = NULL;
- mutex_unlock(&prtd->out_lock);
}
done:
prtd->capture_substream = NULL;
@@ -899,19 +906,15 @@
for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
buf_node = (void *)dma_buf->area + offset;
- mutex_lock(&voip_info.in_lock);
list_add_tail(&buf_node->list,
&voip_info.free_in_queue);
- mutex_unlock(&voip_info.in_lock);
offset = offset + sizeof(struct voip_buf_node);
}
} else {
for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
buf_node = (void *) dma_buf->area + offset;
- mutex_lock(&voip_info.out_lock);
list_add_tail(&buf_node->list,
&voip_info.free_out_queue);
- mutex_unlock(&voip_info.out_lock);
offset = offset + sizeof(struct voip_buf_node);
}
}
@@ -1145,6 +1148,7 @@
static const struct of_device_id msm_voip_dt_match[] = {
{.compatible = "qcom,msm-voip-dsp"},
+ {}
};
MODULE_DEVICE_TABLE(of, msm_voip_dt_match);
@@ -1163,10 +1167,9 @@
memset(&voip_info, 0, sizeof(voip_info));
voip_info.mode = MODE_PCM;
mutex_init(&voip_info.lock);
- mutex_init(&voip_info.in_lock);
- mutex_init(&voip_info.out_lock);
spin_lock_init(&voip_info.dsp_lock);
+ spin_lock_init(&voip_info.dsp_ul_lock);
init_waitqueue_head(&voip_info.out_wait);
init_waitqueue_head(&voip_info.in_wait);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 29c06cb..5f9d4db 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1003,8 +1003,8 @@
} else if (channel_mode == 6) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LFE;
open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
} else if (channel_mode == 8) {
@@ -1187,24 +1187,7 @@
ret = -EINVAL;
goto fail_cmd;
}
- if (perf_mode) {
- for (i = 0; i < num_copps; i++) {
- int tmp;
-
- tmp = afe_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
- rtac_add_adm_device(port_id[i], atomic_read(
- &this_adm.copp_low_latency_id[tmp]),
- path, session_id);
- pr_debug("%s, copp_id: %d\n", __func__,
- atomic_read(
- &this_adm.copp_low_latency_id[tmp]));
- } else {
- pr_debug("%s: Invalid port index %d",
- __func__, tmp);
- }
- }
- } else {
+ if (!perf_mode) {
for (i = 0; i < num_copps; i++)
send_adm_cal(port_id[i], path);
@@ -1473,8 +1456,8 @@
goto fail_cmd;
}
}
- if (!atomic_read(&this_adm.copp_cnt[index]) &&
- !atomic_read(&this_adm.copp_low_latency_cnt[index])) {
+
+ if (!perf_mode) {
pr_debug("%s: remove adm device from rtac\n", __func__);
rtac_remove_adm_device(port_id);
}
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index ce5e816..6615940 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -56,6 +56,9 @@
#define TIMEOUT_MS 1000
#define Q6AFE_MAX_VOLUME 0x3FFF
+#define Q6AFE_MSM_SPKR_PROCESSING 0
+#define Q6AFE_MSM_SPKR_CALIBRATION 1
+
static int pcm_afe_instance[2];
static int proxy_afe_instance[2];
bool afe_close_done[2] = {true, true};
@@ -515,25 +518,31 @@
/*Get spkr protection cfg data*/
get_spk_protection_cfg(&prot_cfg);
- if ((!prot_cfg.mode || prot_cfg.mode == 1) &&
+ if ((prot_cfg.mode != MSM_SPKR_PROT_DISABLED) &&
(this_afe.vi_tx_port == port_id)) {
afe_spk_config.mode_rx_cfg.minor_version = 1;
- afe_spk_config.mode_rx_cfg.mode =
- (uint32_t)prot_cfg.mode;
+ if (prot_cfg.mode == MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_CALIBRATION;
+ else
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_PROCESSING;
if (afe_spk_prot_prepare(port_id,
AFE_PARAM_ID_MODE_VI_PROC_CFG,
&afe_spk_config))
pr_err("%s TX VI_PROC_CFG failed\n", __func__);
- afe_spk_config.vi_proc_cfg.minor_version = 1;
- afe_spk_config.vi_proc_cfg.r0_cali_q24 =
- (uint32_t) prot_cfg.r0;
- afe_spk_config.vi_proc_cfg.t0_cali_q6 =
- (uint32_t) prot_cfg.t0;
- if (afe_spk_prot_prepare(port_id,
- AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
- &afe_spk_config))
- pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
- __func__);
+ if (prot_cfg.mode != MSM_SPKR_PROT_NOT_CALIBRATED) {
+ afe_spk_config.vi_proc_cfg.minor_version = 1;
+ afe_spk_config.vi_proc_cfg.r0_cali_q24 =
+ (uint32_t) prot_cfg.r0;
+ afe_spk_config.vi_proc_cfg.t0_cali_q6 =
+ (uint32_t) prot_cfg.t0;
+ if (afe_spk_prot_prepare(port_id,
+ AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
+ &afe_spk_config))
+ pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
+ __func__);
+ }
}
}
@@ -545,9 +554,13 @@
/*Get spkr protection cfg data*/
get_spk_protection_cfg(&prot_cfg);
- if (!prot_cfg.mode || prot_cfg.mode == 1) {
- afe_spk_config.mode_rx_cfg.mode =
- (uint32_t)prot_cfg.mode;
+ if (prot_cfg.mode != MSM_SPKR_PROT_DISABLED) {
+ if (prot_cfg.mode == MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_CALIBRATION;
+ else
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_PROCESSING;
afe_spk_config.mode_rx_cfg.minor_version = 1;
if (afe_spk_prot_prepare(port_id,
AFE_PARAM_ID_FBSP_MODE_RX_CFG,
@@ -1935,6 +1948,7 @@
goto fail_cmd;
}
pr_debug("%s: mmap handle 0x%x\n", __func__, this_afe.mmap_handle);
+ kfree(mmap_region_cmd);
return 0;
fail_cmd:
kfree(mmap_region_cmd);
@@ -2000,6 +2014,7 @@
if (ret)
pr_err("%s: AFE memory map cmd failed %d\n",
__func__, ret);
+ kfree(mmap_region_cmd);
return ret;
}
int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c2fd2d7..ac26d0c 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -3363,6 +3363,7 @@
u32 lbuf_addr_lsw;
u32 liomode;
u32 io_compressed;
+ int dir = 0;
if (!ac || ac->apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -3380,15 +3381,21 @@
read.seq_id = param->uid;
liomode = (NT_MODE | ASYNC_IO_MODE);
io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
- if (ac->io_mode == liomode)
+ if (ac->io_mode == liomode) {
lbuf_addr_lsw = (read.buf_addr_lsw - 32);
- else if (ac->io_mode == io_compressed)
+ /*legacy wma driver case*/
+ dir = IN;
+ } else if (ac->io_mode == io_compressed) {
lbuf_addr_lsw = (read.buf_addr_lsw - 64);
- else
+ dir = OUT;
+ } else {
lbuf_addr_lsw = read.buf_addr_lsw;
+ dir = OUT;
+ }
- list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
- buf_node = list_entry(ptr, struct asm_buffer_node, list);
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
read.mem_map_handle = buf_node->mmap_hdl;
break;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index e9d0a7e..26d9d48 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -82,7 +82,6 @@
static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
static int voice_send_set_pp_enable_cmd(struct voice_data *v,
uint32_t module_id, int enable);
@@ -841,56 +840,6 @@
return -EINVAL;
}
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v)
-{
- struct mvm_set_widevoice_enable_cmd mvm_set_wv_cmd;
- int ret = 0;
- void *apr_mvm;
- u16 mvm_handle;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_mvm = common.apr_q6_mvm;
-
- if (!apr_mvm) {
- pr_err("%s: apr_mvm is NULL.\n", __func__);
- return -EINVAL;
- }
- mvm_handle = voice_get_mvm_handle(v);
-
- mvm_set_wv_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- mvm_set_wv_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(mvm_set_wv_cmd) -
- APR_HDR_SIZE);
- mvm_set_wv_cmd.hdr.src_port = v->session_id;
- mvm_set_wv_cmd.hdr.dest_port = mvm_handle;
- mvm_set_wv_cmd.hdr.token = 0;
- mvm_set_wv_cmd.hdr.opcode = VSS_IWIDEVOICE_CMD_SET_WIDEVOICE;
-
- mvm_set_wv_cmd.vss_set_wv.enable = v->wv_enable;
-
- v->mvm_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_wv_cmd);
- if (ret < 0) {
- pr_err("Fail: sending mvm set widevoice enable,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->mvm_wait,
- (v->mvm_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-}
-
static int voice_send_set_pp_enable_cmd(struct voice_data *v,
uint32_t module_id, int enable)
{
@@ -1207,7 +1156,9 @@
}
/* Set encoder properties. */
switch (common.mvs_info.media_type) {
- case VSS_MEDIA_ID_EVRC_MODEM: {
+ case VSS_MEDIA_ID_EVRC_MODEM:
+ case VSS_MEDIA_ID_4GV_NB_MODEM:
+ case VSS_MEDIA_ID_4GV_WB_MODEM: {
struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
pr_debug("Setting EVRC min-max rate\n");
@@ -1442,6 +1393,34 @@
return -EINVAL;
}
+static void voc_get_tx_rx_topology(struct voice_data *v,
+ uint32_t *tx_topology_id,
+ uint32_t *rx_topology_id)
+{
+ uint32_t tx_id = 0;
+ uint32_t rx_id = 0;
+
+ if (v->lch_mode == VOICE_LCH_START) {
+ pr_debug("%s: Setting TX and RX topology to NONE for LCH\n",
+ __func__);
+
+ tx_id = VSS_IVOCPROC_TOPOLOGY_ID_NONE;
+ rx_id = VSS_IVOCPROC_TOPOLOGY_ID_NONE;
+ } else {
+ /* Use default topology if invalid value in ACDB */
+ tx_id = get_voice_tx_topology();
+ if (tx_id == 0)
+ tx_id = VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+
+ rx_id = get_voice_rx_topology();
+ if (rx_id == 0)
+ rx_id = VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+ }
+
+ *tx_topology_id = tx_id;
+ *rx_topology_id = rx_id;
+}
+
static int voice_send_set_device_cmd(struct voice_data *v)
{
struct cvp_set_device_cmd cvp_setdev_cmd;
@@ -1472,26 +1451,22 @@
cvp_setdev_cmd.hdr.src_port = v->session_id;
cvp_setdev_cmd.hdr.dest_port = cvp_handle;
cvp_setdev_cmd.hdr.token = 0;
- cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE;
+ cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE_V2;
- /* Use default topology if invalid value in ACDB */
- cvp_setdev_cmd.cvp_set_device.tx_topology_id =
- get_voice_tx_topology();
- if (cvp_setdev_cmd.cvp_set_device.tx_topology_id == 0)
- cvp_setdev_cmd.cvp_set_device.tx_topology_id =
- VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+ voc_get_tx_rx_topology(v,
+ &cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
+ &cvp_setdev_cmd.cvp_set_device_v2.rx_topology_id);
- cvp_setdev_cmd.cvp_set_device.rx_topology_id =
- get_voice_rx_topology();
- if (cvp_setdev_cmd.cvp_set_device.rx_topology_id == 0)
- cvp_setdev_cmd.cvp_set_device.rx_topology_id =
- VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
- cvp_setdev_cmd.cvp_set_device.tx_port_id = v->dev_tx.port_id;
- cvp_setdev_cmd.cvp_set_device.rx_port_id = v->dev_rx.port_id;
+ cvp_setdev_cmd.cvp_set_device_v2.tx_port_id = v->dev_tx.port_id;
+ cvp_setdev_cmd.cvp_set_device_v2.rx_port_id = v->dev_rx.port_id;
+ cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+ cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+ VSS_IVOCPROC_PORT_ID_NONE;
pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
- cvp_setdev_cmd.cvp_set_device.tx_topology_id,
- cvp_setdev_cmd.cvp_set_device.tx_port_id,
- cvp_setdev_cmd.cvp_set_device.rx_port_id);
+ cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
+ cvp_setdev_cmd.cvp_set_device_v2.tx_port_id,
+ cvp_setdev_cmd.cvp_set_device_v2.rx_port_id);
v->cvp_state = CMD_STATUS_FAIL;
ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
@@ -2247,18 +2222,9 @@
cvp_session_cmd.hdr.opcode =
VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2;
- /* Use default topology if invalid value in ACDB */
- cvp_session_cmd.cvp_session.tx_topology_id =
- get_voice_tx_topology();
- if (cvp_session_cmd.cvp_session.tx_topology_id == 0)
- cvp_session_cmd.cvp_session.tx_topology_id =
- VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
-
- cvp_session_cmd.cvp_session.rx_topology_id =
- get_voice_rx_topology();
- if (cvp_session_cmd.cvp_session.rx_topology_id == 0)
- cvp_session_cmd.cvp_session.rx_topology_id =
- VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+ voc_get_tx_rx_topology(v,
+ &cvp_session_cmd.cvp_session.tx_topology_id,
+ &cvp_session_cmd.cvp_session.rx_topology_id);
cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
@@ -2327,20 +2293,11 @@
voice_send_netid_timing_cmd(v);
}
- /* enable widevoice if wv_enable is set */
- if (v->wv_enable)
- voice_send_set_widevoice_enable_cmd(v);
-
/* enable slowtalk if st_enable is set */
if (v->st_enable)
voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
v->st_enable);
-
- voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_FENS,
- v->fens_enable);
-
/* Start in-call music delivery if this feature is enabled */
if (v->music_info.play_enable)
voice_cvs_start_playback(v);
@@ -2643,6 +2600,9 @@
if (v->dtmf_rx_detect_en)
voice_send_dtmf_rx_detection_cmd(v, 0);
+ /* reset LCH mode */
+ v->lch_mode = 0;
+
/* detach VOCPROC and wait for response from mvm */
mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -2882,7 +2842,7 @@
return -EINVAL;
}
-static int voice_send_mute_cmd(struct voice_data *v)
+static int voice_send_stream_mute_cmd(struct voice_data *v)
{
struct cvs_set_mute_cmd cvs_mute_cmd;
int ret = 0;
@@ -2910,7 +2870,7 @@
cvs_mute_cmd.hdr.token = 0;
cvs_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
cvs_mute_cmd.cvs_set_mute.direction = VSS_IVOLUME_DIRECTION_TX;
- cvs_mute_cmd.cvs_set_mute.mute_flag = v->dev_tx.mute;
+ cvs_mute_cmd.cvs_set_mute.mute_flag = v->stream_tx.stream_mute;
cvs_mute_cmd.cvs_set_mute.ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
v->cvs_state = CMD_STATUS_FAIL;
@@ -2935,7 +2895,8 @@
return -EINVAL;
}
-static int voice_send_rx_device_mute_cmd(struct voice_data *v)
+static int voice_send_device_mute_cmd(struct voice_data *v, uint16_t direction,
+ uint16_t mute_flag)
{
struct cvp_set_mute_cmd cvp_mute_cmd;
int ret = 0;
@@ -2961,8 +2922,8 @@
cvp_mute_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_mute_cmd.hdr.token = 0;
cvp_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
- cvp_mute_cmd.cvp_set_mute.direction = VSS_IVOLUME_DIRECTION_RX;
- cvp_mute_cmd.cvp_set_mute.mute_flag = v->dev_rx.mute;
+ cvp_mute_cmd.cvp_set_mute.direction = direction;
+ cvp_mute_cmd.cvp_set_mute.mute_flag = mute_flag;
cvp_mute_cmd.cvp_set_mute.ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
v->cvp_state = CMD_STATUS_FAIL;
@@ -3491,7 +3452,7 @@
int ret = 0;
if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
return -EINVAL;
}
@@ -3501,7 +3462,7 @@
if (v->voc_state == VOC_CHANGE) {
ret = voice_send_set_device_cmd(v);
if (ret < 0) {
- pr_err("%s: set device failed\n", __func__);
+ pr_err("%s: Set device failed\n", __func__);
goto fail;
}
@@ -3509,31 +3470,45 @@
voice_send_cvp_register_cal_cmd(v);
voice_send_cvp_register_vol_cal_cmd(v);
+ if (v->lch_mode == VOICE_LCH_START) {
+ pr_debug("%s: TX and RX mute ON\n", __func__);
+
+ voice_send_device_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_TX,
+ VSS_IVOLUME_MUTE_ON);
+ voice_send_device_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_RX,
+ VSS_IVOLUME_MUTE_ON);
+ } else if (v->lch_mode == VOICE_LCH_STOP) {
+ pr_debug("%s: TX and RX mute OFF\n", __func__);
+
+ voice_send_device_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_TX,
+ VSS_IVOLUME_MUTE_OFF);
+ voice_send_device_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_RX,
+ VSS_IVOLUME_MUTE_OFF);
+ /* Reset lch mode when VOICE_LCH_STOP is recieved */
+ v->lch_mode = 0;
+ } else {
+ pr_debug("%s: Mute commands not sent for lch_mode=%d\n",
+ __func__, v->lch_mode);
+ }
+
ret = voice_send_enable_vocproc_cmd(v);
if (ret < 0) {
- pr_err("%s: enable vocproc failed %d\n", __func__, ret);
+ pr_err("%s: Enable vocproc failed %d\n", __func__, ret);
+
goto fail;
}
/* Send tty mode if tty device is used */
voice_send_tty_mode_cmd(v);
-
- /* enable widevoice if wv_enable is set */
- if (v->wv_enable)
- voice_send_set_widevoice_enable_cmd(v);
-
/* enable slowtalk */
if (v->st_enable)
voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
v->st_enable);
-
- /* enable FENS */
- if (v->fens_enable)
- voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_FENS,
- v->fens_enable);
-
rtac_add_voice(voice_get_cvs_handle(v),
voice_get_cvp_handle(v),
v->dev_rx.port_id, v->dev_tx.port_id,
@@ -3591,12 +3566,12 @@
mutex_lock(&v->lock);
- v->dev_tx.mute = mute;
+ v->stream_tx.stream_mute = mute;
if ((v->voc_state == VOC_RUN) ||
(v->voc_state == VOC_CHANGE) ||
(v->voc_state == VOC_STANDBY))
- ret = voice_send_mute_cmd(v);
+ ret = voice_send_stream_mute_cmd(v);
mutex_unlock(&v->lock);
@@ -3616,10 +3591,12 @@
mutex_lock(&v->lock);
- v->dev_rx.mute = mute;
+ v->dev_rx.dev_mute = mute;
if (v->voc_state == VOC_RUN)
- ret = voice_send_rx_device_mute_cmd(v);
+ ret = voice_send_device_mute_cmd(v,
+ VSS_IVOLUME_DIRECTION_RX,
+ v->dev_rx.dev_mute);
mutex_unlock(&v->lock);
@@ -3639,7 +3616,7 @@
mutex_lock(&v->lock);
- ret = v->dev_rx.mute;
+ ret = v->dev_rx.dev_mute;
mutex_unlock(&v->lock);
@@ -3686,51 +3663,6 @@
return ret;
}
-int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable)
-{
- struct voice_data *v = voice_get_session(session_id);
- u16 mvm_handle;
- int ret = 0;
-
- if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
-
- return -EINVAL;
- }
-
- mutex_lock(&v->lock);
-
- v->wv_enable = wv_enable;
-
- mvm_handle = voice_get_mvm_handle(v);
- if (mvm_handle != 0)
- voice_send_set_widevoice_enable_cmd(v);
-
- mutex_unlock(&v->lock);
-
- return ret;
-}
-
-uint32_t voc_get_widevoice_enable(uint16_t session_id)
-{
- struct voice_data *v = voice_get_session(session_id);
- int ret = 0;
-
- if (v == NULL) {
- pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
-
- return -EINVAL;
- }
-
- mutex_lock(&v->lock);
-
- ret = v->wv_enable;
-
- mutex_unlock(&v->lock);
-
- return ret;
-}
-
int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable)
{
struct voice_data *v = voice_get_session(session_id);
@@ -3745,18 +3677,12 @@
mutex_lock(&v->lock);
if (module_id == MODULE_ID_VOICE_MODULE_ST)
v->st_enable = enable;
- else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
- v->fens_enable = enable;
if (v->voc_state == VOC_RUN) {
if (module_id == MODULE_ID_VOICE_MODULE_ST)
ret = voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
enable);
- else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
- ret = voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_FENS,
- enable);
}
mutex_unlock(&v->lock);
@@ -3778,9 +3704,6 @@
mutex_lock(&v->lock);
if (module_id == MODULE_ID_VOICE_MODULE_ST)
ret = v->st_enable;
- else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
- ret = v->fens_enable;
-
mutex_unlock(&v->lock);
return ret;
@@ -3958,6 +3881,49 @@
return ret;
}
+int voc_set_lch(uint16_t session_id, enum voice_lch_mode lch_mode)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&v->lock);
+ if (v->lch_mode == lch_mode) {
+ pr_debug("%s: Session %d already in LCH mode %d\n",
+ __func__, session_id, lch_mode);
+
+ mutex_unlock(&v->lock);
+ goto done;
+ }
+
+ v->lch_mode = lch_mode;
+ mutex_unlock(&v->lock);
+
+ ret = voc_disable_cvp(session_id);
+ if (ret < 0) {
+ pr_err("%s: voc_disable_cvp failed ret=%d\n", __func__, ret);
+
+ goto done;
+ }
+
+ /* Mute and topology_none will be set as part of voc_enable_cvp() */
+ ret = voc_enable_cvp(session_id);
+ if (ret < 0) {
+ pr_err("%s: voc_enable_cvp failed ret=%d\n", __func__, ret);
+
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
int voc_resume_voice_call(uint16_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
@@ -4179,7 +4145,6 @@
case VSS_IMVM_CMD_DETACH_STREAM:
case VSS_ICOMMON_CMD_SET_NETWORK:
case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
- case VSS_IWIDEVOICE_CMD_SET_WIDEVOICE:
case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
case VSS_IMVM_CMD_SET_CAL_NETWORK:
case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
@@ -4578,7 +4543,7 @@
v->cvp_state = CMD_STATUS_SUCCESS;
wake_up(&v->cvp_wait);
break;
- case VSS_IVOCPROC_CMD_SET_DEVICE:
+ case VSS_IVOCPROC_CMD_SET_DEVICE_V2:
case VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX:
case VSS_IVOCPROC_CMD_ENABLE:
case VSS_IVOCPROC_CMD_DISABLE:
@@ -4767,13 +4732,16 @@
/* initialize dev_rx and dev_tx */
common.voice[i].dev_rx.volume = common.default_vol_val;
- common.voice[i].dev_rx.mute = 0;
- common.voice[i].dev_tx.mute = common.default_mute_val;
+ common.voice[i].dev_rx.dev_mute = 0;
+ common.voice[i].dev_tx.dev_mute = 0;
+ common.voice[i].stream_rx.stream_mute = common.default_mute_val;
+ common.voice[i].stream_tx.stream_mute = common.default_mute_val;
common.voice[i].dev_tx.port_id = 0x100B;
common.voice[i].dev_rx.port_id = 0x100A;
common.voice[i].sidetone_gain = 0x512;
common.voice[i].dtmf_rx_detect_en = 0;
+ common.voice[i].lch_mode = 0;
common.voice[i].voc_state = VOC_INIT;
@@ -4801,4 +4769,4 @@
return rc;
}
-device_initcall(voice_init);
+late_initcall(voice_init);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index ef5c6e3..386634b 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -14,6 +14,7 @@
#include <mach/qdsp6v2/apr.h>
#include <linux/msm_ion.h>
+#include <sound/voice_params.h>
#define MAX_VOC_PKT_SIZE 642
#define SESSION_NAME_LEN 20
@@ -41,11 +42,15 @@
void *cb_handle;
};
-/* Device information payload structure */
+/* Stream information payload structure */
+struct stream_data {
+ uint32_t stream_mute;
+};
+/* Device information payload structure */
struct device_data {
uint32_t volume; /* in index */
- uint32_t mute;
+ uint32_t dev_mute;
uint32_t sample;
uint32_t enabled;
uint32_t dev_id;
@@ -194,9 +199,6 @@
#define VSS_ICOMMON_CMD_SET_VOICE_TIMING 0x000111E0
/* Set the voice timing parameters. */
-#define VSS_IWIDEVOICE_CMD_SET_WIDEVOICE 0x00011243
-/* Enable/disable WideVoice */
-
#define VSS_IMEMORY_CMD_MAP_PHYSICAL 0x00011334
#define VSS_IMEMORY_RSP_MAP 0x00011336
#define VSS_IMEMORY_CMD_UNMAP 0x00011337
@@ -291,14 +293,6 @@
/* Set to TRUE to enable modem state machine control */
} __packed;
-struct vss_iwidevoice_cmd_set_widevoice_t {
- uint32_t enable;
- /* WideVoice enable/disable; possible values:
- * - 0 -- WideVoice disabled
- * - 1 -- WideVoice enabled
- */
-} __packed;
-
struct mvm_attach_vocproc_cmd {
struct apr_hdr hdr;
struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
@@ -344,11 +338,6 @@
struct vss_icommon_cmd_set_voice_timing_t timing;
} __packed;
-struct mvm_set_widevoice_enable_cmd {
- struct apr_hdr hdr;
- struct vss_iwidevoice_cmd_set_widevoice_t vss_set_wv;
-} __packed;
-
struct vss_imemory_table_descriptor_t {
uint64_t mem_address;
/*
@@ -484,7 +473,6 @@
#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE 0x0001101D
/* Set encoder DTX mode. */
-#define MODULE_ID_VOICE_MODULE_FENS 0x00010EEB
#define MODULE_ID_VOICE_MODULE_ST 0x00010EE3
#define VOICE_PARAM_MOD_ENABLE 0x00010E00
#define MOD_ENABLE_PARAM_LEN 4
@@ -904,7 +892,7 @@
#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
-#define VSS_IVOCPROC_CMD_SET_DEVICE 0x000100C4
+#define VSS_IVOCPROC_CMD_SET_DEVICE_V2 0x000112C6
#define VSS_IVOCPROC_CMD_SET_VP3_DATA 0x000110EB
@@ -1042,8 +1030,8 @@
*/
} __packed;
-struct vss_ivocproc_cmd_set_device_t {
- uint32_t tx_port_id;
+struct vss_ivocproc_cmd_set_device_v2_t {
+ uint16_t tx_port_id;
/*
* TX device port ID which vocproc will connect to.
* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
@@ -1054,7 +1042,7 @@
* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
* pre/post-processing blocks and is pass-through.
*/
- int32_t rx_port_id;
+ uint16_t rx_port_id;
/*
* RX device port ID which vocproc will connect to.
* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
@@ -1065,6 +1053,15 @@
* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
* pre/post-processing blocks and is pass-through.
*/
+ uint32_t vocproc_mode;
+ /* Vocproc mode. The supported values:
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING - 0x00010F7C
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING - 0x00010F7D
+ */
+ uint16_t ec_ref_port_id;
+ /* Port ID to which the vocproc connects for receiving
+ * echo
+ */
} __packed;
struct vss_ivocproc_cmd_register_device_config_t {
@@ -1128,7 +1125,7 @@
struct cvp_set_device_cmd {
struct apr_hdr hdr;
- struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+ struct vss_ivocproc_cmd_set_device_v2_t cvp_set_device_v2;
} __packed;
struct cvp_set_vp3_data_cmd {
@@ -1230,10 +1227,14 @@
wait_queue_head_t cvs_wait;
wait_queue_head_t cvp_wait;
- /* cache the values related to Rx and Tx */
+ /* Cache the values related to Rx and Tx devices */
struct device_data dev_rx;
struct device_data dev_tx;
+ /* Cache the values related to Rx and Tx streams */
+ struct stream_data stream_rx;
+ struct stream_data stream_tx;
+
u32 mvm_state;
u32 cvs_state;
u32 cvp_state;
@@ -1249,14 +1250,11 @@
uint16_t sidetone_gain;
uint8_t tty_mode;
- /* widevoice enable value */
- uint8_t wv_enable;
/* slowtalk enable value */
uint32_t st_enable;
- /* FENC enable value */
- uint32_t fens_enable;
-
uint32_t dtmf_rx_detect_en;
+ /* Local Call Hold mode */
+ uint8_t lch_mode;
struct voice_dev_route_state voc_route_state;
@@ -1345,14 +1343,13 @@
int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
uint32_t enable);
int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
-int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
-uint32_t voc_get_widevoice_enable(uint16_t session_id);
uint8_t voc_get_tty_mode(uint16_t session_id);
int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode);
int voc_start_voice_call(uint16_t session_id);
int voc_end_voice_call(uint16_t session_id);
int voc_standby_voice_call(uint16_t session_id);
int voc_resume_voice_call(uint16_t session_id);
+int voc_set_lch(uint16_t session_id, enum voice_lch_mode lch_mode);
int voc_set_rxtx_port(uint16_t session_id,
uint32_t dev_port_id,
uint32_t dev_type);