Merge "arm/dt: msm8610: add Himax WVGA panel support for msm8610-QRD"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 439418d..04310ec 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -12,9 +12,10 @@
Required properties:
- compatible: Must be "qcom,cpr-regulator"
-- reg: Register addresses for RBCPR and efuse
-- reg-names: Register names. Must be "rbcpr", "pvs_efuse"
- and "cpr_efuse"
+- reg: Register addresses for RBCPR, RBCPR clock
+ select, PVS eFuse and CPR eFuse
+- reg-names: Register names. Must be "rbcpr", "rbcpr_clk",
+ "pvs_efuse" and "cpr_efuse"
- regulator-name: A string used to describe the regulator
- interrupts: Interrupt line from RBCPR to interrupt controller.
- regulator-min-microvolt: Minimum corner value as min constraint, which
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index c1b79ae..6dac1b7 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -69,3 +69,20 @@
This region is assumed to be a part of a separate hole that has been removed
and this binding specifies the fixed location and size of the region within
that hole.
+
+
+Some drivers may only wish to reserve memory from the system. Reserved memory
+is still tracked internally by the Linux page allocator. The memory is reserved
+from the buddy allocator at bootup but may be freed back at a later point in
+time with memblock_free and free_bootmem_late.
+
+Required parameters:
+-qcom,memblock-reserve: base and size of block to be reserved. Drivers should
+call memblock_is_reserved before attempting to use the base address to ensure
+the memory was completely reserved.
+
+ qcom,a-driver {
+ compatible = "qcom,a-driver";
+ /* reserve a 4MB region @ 0x200000 for use later */
+ qcom,memblock-reserve = <0x200000 0x400000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index 6b2f962..fbf1a1f 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -91,6 +91,31 @@
(Can be 0/1/2).
qcom,prio1: Priority high signal for a NoC bus master
(Can be 0/1/2)
+qcom,dual-conf: Indicates whether a BIMC/NoC master can be configured
+ in multiple modes at run-time. (Boolean)
+qcom,mode-thresh: Threshold mode for a BIMC/NoC master. Beyond a certain
+ threshold frequency, a threshold mode can be used.
+ (Can be Fixed/Limiter/Bypass/Regulator)
+qcom,bimc,bw: Bandwidth limit for a BIMC master using dual modes.
+ This bandwidth is used to calculate Grant count and
+ other parameters used in Limiter and Regular mode
+ for static BKE configuration. It is defined in KBps.
+qcom,bimc,gp: Grant Period for configuring a master in limiter
+ mode. This is an integer value in micro-seconds.
+qcom,bimc,thmp: Medium threshold percentage for BIMC masters.
+ This percentage is used to calculate medium threshold
+ value for BIMC Masters in Limiter mode for static
+ configuration. This can be any integer value between
+ 1 and 100.
+qcom,thresh: Beyond this threshold frequency, the mode usage is
+ switched from mode specified by property qcom,mode
+ to the one specified by qcom,mode-thresh. In case the
+ requested IB value falls below this threshold, the mode
+ is switched back to qcom,mode. Frequency is specified in
+ KBps.
+
+
+
Example:
@@ -135,6 +160,45 @@
};
};
+ msm-bimc@0xfc380000 {
+ compatible = "msm-bus-fabric";
+ reg = <0xfc380000 0x0006A000>;
+ cell-id = <0>;
+ label = "msm_bimc";
+ qcom,fabclk-dual = "mem_clk";
+ qcom,fabclk-active = "mem_a_clk";
+ qcom,ntieredslaves = <0>;
+ qcom,qos-freq = <19200>;
+ qcom,hw-sel = "BIMC";
+ qcom,rpm-en;
+
+ coresight-id = <55>;
+ coresight-name = "coresight-bimc";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <3>;
+
+ mas-ampss-m0 {
+ cell-id = <1>;
+ label = "mas-ampss-m0";
+ qcom,masterp = <0>;
+ qcom,tier = <2>;
+ qcom,hw-sel = "BIMC";
+ qcom,mode = "Limiter";
+ qcom,qport = <0>;
+ qcom,ws = <10000>;
+ qcom,mas-hw-id = <0>;
+ qcom,prio-rd = <0>;
+ qcom,prio-wr = <0>;
+ qcom,mode-thresh = "Fixed";
+ qcom,thresh = <2000000>;
+ qcom,dual-conf;
+ qcom,bimc,bw = <300000>;
+ qcom,bimc,gp = <5>;
+ qcom,bimc,thmp = <50>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
index cfda474..5692ad2 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
@@ -34,6 +34,13 @@
Some hardware platforms (e.g. 8974-v2) require the voltage of the rail
supplying power to the TSIF hardware block to be elevated before
enabling the TSIF clocks.
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+ the below optional properties:
+ - qcom,msm-bus,name
+ - qcom,msm-bus,num-cases
+ - qcom,msm-bus,active-only
+ - qcom,msm-bus,num-paths
+ - qcom,msm-bus,vectors-KBps
Example (for 8974 platform, avaialble at msm8974.dtsi):
@@ -75,6 +82,14 @@
"tsif_data",
"tsif_sync";
qcom,gpios-func = <1>;
+
+ qcom,msm-bus,name = "tsif";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <82 512 0 0>, /* No vote */
+ <82 512 12288 24576>; /* Max. bandwidth, 2xTSIF, each max of 96Mbps */
};
diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt
index 1c044eb..19472c9 100644
--- a/Documentation/devicetree/bindings/arm/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/pmu.txt
@@ -9,6 +9,7 @@
- compatible : should be one of
"arm,cortex-a9-pmu"
"arm,cortex-a8-pmu"
+ "arm,cortex-a7-pmu"
"arm,arm1176-pmu"
"arm,arm1136-pmu"
- interrupts : 1 combined interrupt or 1 per core.
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index 7eb65d2..3ca9080 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -15,8 +15,7 @@
Optional properties:
- qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE.
-
-
+ - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY.
Example:
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 79dc287..01cc798 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -15,7 +15,7 @@
Optional properties:
- qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE.
-
+ - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY.
Example:
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 052feeb..aa0aa8c 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -66,7 +66,6 @@
and when coming back out of resume
- qcom,step-pwrlevel: How many qcom,gpu-pwrlevel should be decremented at once
- qcom,idle-timeout: This property represents the time in microseconds for idle timeout.
-- qcom,nap-allowed: Boolean. <0> or <1> to disable/enable nap.
- qcom,chipid: If it exists this property is used to replace
the chip identification read from the GPU hardware.
This is used to override faulty hardware readings.
@@ -105,7 +104,6 @@
qcom,initial-pwrlevel = <1>;
qcom,idle-timeout = <83>; //<HZ/12>
- qcom,nap-allowed = <1>;
qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
/* Bus Scale Settings */
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
new file mode 100644
index 0000000..d77e96c
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
@@ -0,0 +1,53 @@
+FocalTech touch controller
+
+The focaltech controller is connected to host processor
+via i2c. The controller generates interrupts when the
+user touches the panel. The host controller is expected
+to read the touch coordinates over i2c and pass the coordinates
+to the rest of the system.
+
+Required properties:
+
+ - compatible : should be "focaltech,5x06"
+ - reg : i2c slave address of the device
+ - interrupt-parent : parent of interrupt
+ - interrupts : touch sample interrupt to indicate presense or release
+ of fingers on the panel.
+ - vdd-supply : Power supply needed to power up the device
+ - vcc_i2c-supply : Power source required to power up i2c bus
+ - focaltech,family-id : family identification of the controller
+ - focaltech,irq-gpio : irq gpio which is to provide interrupts to host,
+ same as "interrupts" node. It will also
+ contain active low or active high information.
+ - focaltech,reset-gpio : reset gpio to control the reset of chip
+ - focaltech,display-coords : display coordinates in pixels. It is a four
+ tuple consisting of min x, min y, max x and
+ max y values
+
+Optional properties:
+
+ - focaltech,panel-coords : panel coordinates for the chip in pixels.
+ It is a four tuple consisting of min x,
+ min y, max x and max y values
+ - focaltech,i2c-pull-up : to specify pull up is required
+ - focaltech,no-force-update : to specify force update is allowed
+ - focaltech,button-map : button map of key codes. The number
+ of key codes depend on panel
+
+Example:
+ i2c@f9924000 {
+ ft5x06_ts@38 {
+ compatible = "focaltech,5x06";
+ reg = <0x38>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd-supply = <&pm8941_l22>;
+ vcc_i2c-supply = <&pm8941_s3>;
+ focaltech,reset-gpio = <&msmgpio 60 0x00>;
+ focaltech,irq-gpio = <&msmgpio 61 0x00>;
+ focaltech,panel-coords = <0 0 480 800>;
+ focaltech,display-coords = <0 0 480 800>;
+ focaltech,button-map= <158 102 139 217>;
+ focaltech,family-id = <0x0a>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index d24139b..0f35e73 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -12,7 +12,6 @@
Optional property:
- vdd-supply : Analog power supply needed to power device
- - synaptics,reg-en : specify to indicate regulator is needed
- vcc_i2c-supply : Power source required to pull up i2c bus
- synaptics,i2c-pull-up : specify to indicate pull up is needed
- synaptics,button-map : virtual key code mappings to be used
@@ -48,6 +47,5 @@
synaptics,irq-gpio = <&msmgpio 17 0x00>;
synaptics,button-map = [8B 66 9E];
synaptics,i2c-pull-up;
- synaptics,reg-en;
};
};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index ed45979..26a119c 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -13,6 +13,7 @@
- qcom,iommu-secure-id : Secure identifier for the IOMMU block
- qcom,secure-context : boolean indicating that a context is secure and
programmed by the secure environment.
+- qcom,vdd-supply: Regulator needed to access IOMMU
- qcom,alt-vdd-supply : Alternative regulator needed to access IOMMU
configuration registers.
- interrupts : should contain the performance monitor overflow interrupt number.
@@ -28,7 +29,10 @@
- compatible : "qcom,msm-smmu-v1-ctx"
- reg : offset and length of the register set for the context bank.
- - interrupts : should contain the context bank interrupt.
+ - interrupts : should contain the context bank interrupt. If this is
+ a secure context bank, this should be a list of 2 3-tuples where
+ the first is the non-secure interrupt, and the second is the
+ secure interrupt.
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
translation context.
- label : Name of the context bank
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index ae1f648..ff95d43 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -46,6 +46,7 @@
- linux,default-trigger: trigger the led from external modules such as display
- qcom,default-state: default state of the led, should be "on" or "off"
- qcom,torch-enable: set flash led to torch mode
+- flash_boost-supply: SMBB regulator for LED flash mode
RGB Led is a tri-colored led, Red, Blue & Green.
@@ -70,6 +71,7 @@
- linux,default-trigger: trigger the led from external modules such as display
- qcom,default-state: default state of the led, should be "on" or "off"
- qcom,turn-off-delay-ms: delay in millisecond for turning off the led when its default-state is "on". Value is being ignored in case default-state is "off".
+- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
MPP LED is an LED controled through a Multi Purpose Pin.
@@ -79,6 +81,7 @@
- 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"
+- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
@@ -160,8 +163,19 @@
label = "rgb";
linux,name = "led:rgb_red";
qcom,mode = "pwm";
- qcom,pwm-channel = <6>;
qcom,pwm-us = <1000>;
+ qcom,pwm-channel = <6>;
+ qcom,max-current = <12>;
+ qcom,default-state = "off";
+ qcom,id = <3>;
+ linux,default-trigger =
+ "battery-charging";
+ };
+ qcom,rgb_lpg {
+ label = "rgb";
+ linux,name = "led:rgb_green";
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
qcom,duty-ms = <20>;
qcom,start-idx = <1>;
qcom,idx-len = <10>;
@@ -174,10 +188,10 @@
"battery-charging";
};
- qcom,rgb_lpg {
+ qcom,rgb_blink {
label = "rgb";
linux,name = "led:rgb_blue";
- qcom,mode = "lpg";
+ qcom,mode = "pwm";
qcom,pwm-channel = <4>;
qcom,start-idx = <1>;
qcom,idx-len = <10>;
@@ -192,12 +206,15 @@
qcom,turn-off-delay-ms = <500>;
qcom,id = <5>;
linux,default-trigger = "none";
+ qcom,pwm-us = <1000>;
+ qcom,use-blink;
};
};
qcom,leds@d300 {
compatible = "qcom,leds-qpnp";
status = "okay";
+ flash_boost-supply = <&pm8941_chg_boost>;
qcom,flash_0 {
qcom,max-current = <1000>;
qcom,default-state = "off";
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 1836867..a2503cd 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -51,9 +51,6 @@
- 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
@@ -133,6 +130,10 @@
property should contain phandle of respective actuator node
- qcom,led-flash-src : if LED flash is supported by this sensor, this
property should contain phandle of respective LED flash node
+- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
+ supplied
+- qcom,vdd-cx-name : should contain names of cx regulator
+
* Qualcomm MSM ACTUATOR
Required properties:
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index ded8f77..d6980ac 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -20,6 +20,8 @@
- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
the apps.
- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
+- qcom,gpio-stop-ack: GPIO used by the modem to ack force stop or a graceful stop
+ to the apps.
Optional properties:
- vdd_mss-supply: Reference to the regulator that supplies the processor.
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 43df9cc..6e125f2 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -63,7 +63,7 @@
"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
+ If the property is not set, the temperatue pin will
be used.
- otg-parent-supply Specify a phandle to a parent supply regulator
for the OTG regulator.
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 74ea2cd..4c6569e 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -467,6 +467,12 @@
- qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
+
+* APQ8074 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,apq8074-audio-taiko"
+
Example:
sound {
@@ -686,6 +692,9 @@
prim-gpio-prim : Primary AUXPCM shares GPIOs with Primary MI2S
prim-gpio-tert : Primary AUXPCM shares GPIOs with Tertiary MI2S
+Optional Properties:
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+
Example:
sound {
@@ -697,4 +706,5 @@
qcom,prim-auxpcm-gpio-din = <&msmgpio 65 0>;
qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index b0d6b4d..a3a9935 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -40,8 +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:
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/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 82ac057..8d41295 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -15,6 +15,7 @@
denx Denx Software Engineering
epson Seiko Epson Corp.
est ESTeem Wireless Modems
+focaltech Focaltech systems
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 6df1efe..d0bbc47 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -18,12 +18,14 @@
- qcom,iris-vddpa-supply : regulator to supply RF PA.
- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
-- 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
+- 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
+- qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
should be performed during boot up.
+- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
+using a smaller count for this buffer will reduce the memory usage.
Example:
@@ -45,6 +47,6 @@
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
<&msmgpio 39 0>, <&msmgpio 40 0>;
- qcom,has_48mhz_xo;
- qcom,has_pronto_hw;
+ qcom,has-48mhz-xo;
+ qcom,has-pronto-hw;
};
diff --git a/Makefile b/Makefile
index 75b36ae..be32c2f 100644
--- a/Makefile
+++ b/Makefile
@@ -563,7 +563,7 @@
all: vmlinux
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS += -Os
+KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
else
KBUILD_CFLAGS += -O2
endif
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/apq8026-mtp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/apq8026-mtp.dts
index dcf4f92..e14a6856 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/apq8026-mtp.dts
@@ -10,13 +10,13 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "apq8026.dtsi"
+/include/ "msm8226-mtp.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm APQ 8026 MTP";
+ compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
+ qcom,msm-id = <199 8 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/apq8026-xpm.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/apq8026-xpm.dts
index dcf4f92..67152af 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/apq8026-xpm.dts
@@ -10,13 +10,13 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "apq8026.dtsi"
+/include/ "msm8226-cdp.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm APQ 8026 XPM";
+ compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
+ qcom,msm-id = <199 14 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/apq8026.dtsi
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/apq8026.dtsi
index dcf4f92..db6576a 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/apq8026.dtsi
@@ -10,13 +10,15 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/*
+ * Only 8026-specific property overrides should be placed inside this
+ * file. Device definitions should be placed inside the msm8226.dtsi
+ * file.
+ */
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "msm8226.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm APQ 8026";
+ compatible = "qcom,apq8026";
+};
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 5700b8d..6b4d1d3 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -11,9 +11,10 @@
*/
/include/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "msm8974-camera-sensor-dragonboard.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -198,6 +199,26 @@
"DMIC6", "MIC BIAS4 External",
"MIC BIAS4 External", "Digital Mic6";
};
+
+ qcom,pronto@fb21b000 {
+ status = "disabled";
+ };
+
+ qcom,iris-fm {
+ status = "disabled";
+ };
+
+ qcom,wcnss-wlan@fb000000 {
+ status = "disabled";
+ };
+
+ qcom,smd-wcnss {
+ status = "disabled";
+ };
+
+ qcom,smsm-wcnss {
+ status = "disabled";
+ };
};
&mdss_fb0 {
@@ -539,12 +560,12 @@
qcom,cs-out-en;
qcom,op-fdbck = <1>;
qcom,default-state = "on";
- qcom,max-current = <25>;
+ qcom,max-current = <20>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <1>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
@@ -555,25 +576,25 @@
&pm8941_chg {
status = "ok";
- qcom,chg-charging-disabled;
+ qcom,charging-disabled;
- qcom,chg-chgr@1000 {
+ qcom,chgr@1000 {
status = "ok";
};
- qcom,chg-buck@1100 {
+ qcom,buck@1100 {
status = "ok";
};
- qcom,chg-usb-chgpth@1300 {
+ qcom,usb-chgpth@1300 {
status = "ok";
};
- qcom,chg-dc-chgpth@1400 {
+ qcom,dc-chgpth@1400 {
status = "ok";
};
- qcom,chg-boost@1500 {
+ qcom,boost@1500 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/apq8074-v2.dtsi b/arch/arm/boot/dts/apq8074-v2.dtsi
index 9c93ed4..76eb14b 100644
--- a/arch/arm/boot/dts/apq8074-v2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.dtsi
@@ -36,6 +36,10 @@
<55 512 3936000 393600>,
<55 512 3936000 393600>;
};
+
+ sound {
+ compatible = "qcom,apq8074-audio-taiko";
+ };
};
&memory_hole {
diff --git a/arch/arm/boot/dts/apq8084-regulator.dtsi b/arch/arm/boot/dts/apq8084-regulator.dtsi
index 00991b3..998b469 100644
--- a/arch/arm/boot/dts/apq8084-regulator.dtsi
+++ b/arch/arm/boot/dts/apq8084-regulator.dtsi
@@ -325,3 +325,53 @@
};
};
+&rpm_bus {
+ rpm-regulator-smpb1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpb";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+
+ pma8084_s1_ao: regulator-s1-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s1_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ };
+ };
+
+ rpm-regulator-smpb2 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpb";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+
+ pma8084_s2_corner_ao: regulator-s2-corner-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_s2_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+
+ pma8084_l12_ao: regulator-l12-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8084_l12_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index c74e59d..d4adb2a 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -136,6 +136,21 @@
#interrupt-cells = <3>;
};
+ i2c_0: i2c@f9925000 { /* BLSP1 QUP3 */
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9925000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 97 0>;
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <50000000>;
+ qcom,sda-gpio = <&msmgpio 10 0>;
+ qcom,scl-gpio = <&msmgpio 11 0>;
+ };
+
usb3: qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xf9200000 0xfc000>,
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
index a3718aa..891eac3 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -55,62 +55,62 @@
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
qcom,panel-on-cmds = [
- 05 01 00 00 01 02
+ 05 01 00 00 00 02
01 00
- 23 01 00 00 01 02
+ 23 01 00 00 00 02
b0 04
- 29 01 00 00 01 03
+ 29 01 00 00 00 03
b3 02 00
- 23 01 00 00 01 02
+ 23 01 00 00 00 02
bd 00
- 29 01 00 00 01 03
+ 29 01 00 00 00 03
c0 18 66
- 29 01 00 00 01 10
+ 29 01 00 00 00 10
c1 23 31 99 21 20 00 30 28 0c 0c
00 00 00 21 01
- 29 01 00 00 01 07
+ 29 01 00 00 00 07
c2 10 06 06 01 03 00
- 29 01 00 00 01 19
+ 29 01 00 00 00 19
c8 04 10 18 20 2e 46 3c 28 1f 18
10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
- 29 01 00 00 01 19
+ 29 01 00 00 00 19
c9 04 10 18 20 2e 46 3c 28 1f 18
10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
- 29 01 00 00 01 19
+ 29 01 00 00 00 19
ca 04 10 18 20 2e 46 3c 28 1f 18
10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
- 29 01 00 00 01 11
+ 29 01 00 00 00 11
d0 29 03 ce a6 00 43 20 10 01 00
01 01 00 03 01 00
- 29 01 00 00 01 08
+ 29 01 00 00 00 08
d1 18 0C 23 03 75 02 50
- 23 01 00 00 01 02
+ 23 01 00 00 00 02
d3 11
- 29 01 00 00 01 03
+ 29 01 00 00 00 03
d5 2a 2a
- 29 01 00 00 01 03
+ 29 01 00 00 00 03
de 01 41
- 23 01 00 00 01 02
+ 23 01 00 00 00 02
e6 51
- 23 01 00 00 01 02
+ 23 01 00 00 00 02
fa 03
23 01 00 00 64 02
d6 28
- 39 01 00 00 01 05
+ 39 01 00 00 00 05
2a 00 00 01 df
- 39 01 00 00 01 05
+ 39 01 00 00 00 05
2b 00 00 03 1f
- 15 01 00 00 01 02
+ 15 01 00 00 00 02
35 00
- 39 01 00 00 01 03
+ 39 01 00 00 00 03
44 00 50
- 15 01 00 00 01 02
+ 15 01 00 00 00 02
36 c1
- 15 01 00 00 01 02
+ 15 01 00 00 00 02
3a 77
- 05 01 00 00 96 02
+ 05 01 00 00 7D 02
11 00
- 05 01 00 00 64 02
+ 05 01 00 00 14 02
29 00
];
qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
index c6693e1..56369dc 100644
--- a/arch/arm/boot/dts/mpq8092-iommu.dtsi
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -14,20 +14,27 @@
&jpeg_iommu {
status = "ok";
+ vdd-supply = <&gdsc_jpeg>;
};
&mdp_iommu {
status = "ok";
+ vdd-supply = <&gdsc_mdss>;
};
&venus_iommu {
status = "ok";
+ vdd-supply = <&gdsc_venus>;
};
&kgsl_iommu {
status = "ok";
+ qcom,needs-alt-core-clk;
+ vdd-supply = <&gdsc_oxili_cx>;
+ qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
};
&vfe_iommu {
status = "ok";
+ vdd-supply = <&gdsc_vfe>;
};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 4dea9e0..cc19cce 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -69,6 +69,11 @@
status = "disabled";
};
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+
spmi_bus: qcom,spmi@fc4c0000 {
cell-index = <0>;
compatible = "qcom,spmi-pmic-arb";
@@ -130,6 +135,15 @@
reg = <0xfc580000 0x17c>;
interrupts = <0 243 0>;
};
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping;
+ };
};
&gdsc_venus {
@@ -144,10 +158,6 @@
status = "ok";
};
-&gdsc_vfe {
- status = "ok";
-};
-
&gdsc_oxili_gx {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index ab46861..4492077 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -19,10 +19,16 @@
reg = <0xfda64000 0x10000>;
reg-names = "iommu_base";
interrupts = <0 67 0>;
- vdd-supply = <&gdsc_jpeg>;
qcom,needs-alt-core-clk;
label = "jpeg_iommu";
status = "disabled";
+ qcom,msm-bus,name = "jpeg_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <62 512 0 0>,
+ <62 512 0 1000>;
qcom,iommu-pmu-ngroups = <1>;
qcom,iommu-pmu-ncounters = <8>;
@@ -109,9 +115,15 @@
reg = <0xfd928000 0x10000>;
reg-names = "iommu_base";
interrupts = <0 73 0>;
- vdd-supply = <&gdsc_mdss>;
qcom,iommu-secure-id = <1>;
label = "mdp_iommu";
+ qcom,msm-bus,name = "mdp_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-pmu-ngroups = <1>;
@@ -183,7 +195,7 @@
qcom,iommu-ctx@fd931000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd931000 0x1000>;
- interrupts = <0 47 0>;
+ interrupts = <0 47 0>, <0 46 0>;
qcom,iommu-ctx-sids = <1>;
label = "mdp_1";
qcom,secure-context;
@@ -192,7 +204,7 @@
qcom,iommu-ctx@fd932000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd932000 0x1000>;
- interrupts = <0 47 0>;
+ interrupts = <0 47 0>, <0 46 0>;
qcom,iommu-ctx-sids = <>;
label = "mdp_2";
qcom,secure-context;
@@ -208,10 +220,16 @@
0xfdce0004 0x4>;
reg-names = "iommu_base", "clk_base";
interrupts = <0 45 0>;
- vdd-supply = <&gdsc_venus>;
qcom,iommu-secure-id = <0>;
qcom,needs-alt-core-clk;
label = "venus_iommu";
+ qcom,msm-bus,name = "venus_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <63 512 0 0>,
+ <63 512 0 1000>;
status = "disabled";
qcom,iommu-pmu-ngroups = <1>;
@@ -295,7 +313,7 @@
venus_cp: qcom,iommu-ctx@fdc8d000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8d000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
label = "venus_cp";
qcom,secure-context;
@@ -304,7 +322,7 @@
venus_fw: qcom,iommu-ctx@fdc8e000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8e000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0xc0 0xc6>;
label = "venus_fw";
qcom,secure-context;
@@ -319,10 +337,14 @@
reg = <0xfdb10000 0x10000>;
reg-names = "iommu_base";
interrupts = <0 38 0>;
- vdd-supply = <&gdsc_oxili_cx>;
- qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
- qcom,needs-alt-core-clk;
label = "kgsl_iommu";
+ qcom,msm-bus,name = "kgsl_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-pmu-ngroups = <1>;
@@ -396,9 +418,15 @@
reg = <0xfda44000 0x10000>;
reg-names = "iommu_base";
interrupts = <0 62 0>;
- vdd-supply = <&gdsc_vfe>;
qcom,needs-alt-core-clk;
label = "vfe_iommu";
+ 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-pmu-ngroups = <1>;
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index e1f0e61..1877f40 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -53,7 +53,7 @@
status = "disabled";
qcom,vddmax-mv = <4200>;
- qcom,vddsafe-mv = <4200>;
+ qcom,vddsafe-mv = <4230>;
qcom,vinmin-mv = <4200>;
qcom,vbatdet-mv = <4100>;
qcom,ibatmax-ma = <1500>;
@@ -265,6 +265,30 @@
};
};
+ pm8110_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,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0>;
+ label = "pm8110_tz";
+ qcom,channel-num = <8>;
+ qcom,threshold-set = <0>;
+ };
+
pm8110_bms: qcom,bms {
spmi-dev-container;
compatible = "qcom,qpnp-bms";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 128d90c..d429f72 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -57,7 +57,7 @@
status = "disabled";
qcom,vddmax-mv = <4200>;
- qcom,vddsafe-mv = <4200>;
+ qcom,vddsafe-mv = <4230>;
qcom,vinmin-mv = <4200>;
qcom,vbatdet-delta-mv = <150>;
qcom,ibatmax-ma = <1500>;
@@ -125,7 +125,7 @@
};
- qcom,usb-chgpth@1300 {
+ pm8226_chg_otg: qcom,usb-chgpth@1300 {
status = "disabled";
reg = <0x1300 0x100>;
interrupts = <0 0x13 0x0>,
@@ -137,7 +137,7 @@
"chg-gone";
};
- qcom,boost@1500 {
+ pm8226_chg_boost: qcom,boost@1500 {
status = "disabled";
reg = <0x1500 0x100>;
interrupts = <0x0 0x15 0x0>,
@@ -415,6 +415,15 @@
qcom,adc-vdd-reference = <1800>;
};
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0>;
+ label = "pm8226_tz";
+ qcom,channel-num = <8>;
+ qcom,threshold-set = <0>;
+ };
+
qcom,pm8226_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
@@ -784,9 +793,10 @@
qcom,leds@d300 {
compatible = "qcom,leds-qpnp";
- status = "disable";
+ status = "okay";
reg = <0xd300 0x100>;
label = "flash";
+ flash_boost-supply = <&pm8226_chg_boost>;
pm8226_flash0: qcom,flash_0 {
qcom,max-current = <1000>;
qcom,default-state = "off";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 85a5608..b4e557e 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -173,7 +173,7 @@
status = "disabled";
qcom,vddmax-mv = <4200>;
- qcom,vddsafe-mv = <4200>;
+ qcom,vddsafe-mv = <4230>;
qcom,vinmin-mv = <4300>;
qcom,ibatmax-ma = <1500>;
qcom,ibatterm-ma = <100>;
@@ -1230,6 +1230,7 @@
compatible = "qcom,leds-qpnp";
reg = <0xd300 0x100>;
label = "flash";
+ flash_boost-supply = <&pm8941_chg_boost>;
};
qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dtsi
similarity index 96%
rename from arch/arm/boot/dts/msm8226-cdp.dts
rename to arch/arm/boot/dts/msm8226-cdp.dtsi
index 6bbdf9f..e489dbb 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -10,20 +10,9 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-/include/ "msm8226.dtsi"
/include/ "dsi-panel-nt35590-720p-video.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
-/ {
- model = "Qualcomm MSM 8226 CDP";
- compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
- qcom,msm-id = <145 1 0>,
- <158 1 0>,
- <159 1 0>,
- <198 1 0>;
-};
-
&soc {
serial@f991f000 {
status = "ok";
@@ -45,7 +34,6 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
- synaptics,reg-en;
};
};
@@ -311,7 +299,7 @@
qcom,cs-out-en;
qcom,op-fdbck = <1>;
qcom,default-state = "on";
- qcom,max-current = <25>;
+ qcom,max-current = <20>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
@@ -395,3 +383,7 @@
qcom,charging-disabled;
qcom,use-default-batt-values;
};
+
+&usb_otg_sw {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index d83df1e..590f733 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -25,7 +25,6 @@
qcom,initial-pwrlevel = <1>;
qcom,idle-timeout = <8>; //<HZ/12>
- qcom,nap-allowed = <1>;
qcom,strtstp-sleepwake;
qcom,clk-map = <0x00000016>; /* KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE */
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
index 460068b..ff3e0a5 100644
--- a/arch/arm/boot/dts/msm8226-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -14,6 +14,7 @@
&jpeg_iommu {
status = "ok";
+ vdd-supply = <&gdsc_jpeg>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
@@ -51,6 +52,7 @@
&mdp_iommu {
status = "ok";
+ vdd-supply = <&gdsc_mdss>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
@@ -94,6 +96,7 @@
&venus_iommu {
status = "ok";
+ vdd-supply = <&gdsc_venus>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
@@ -157,7 +160,10 @@
&kgsl_iommu {
status = "ok";
+ vdd-supply = <&gdsc_oxili_cx>;
+ qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
qcom,iommu-enable-halt;
+ qcom,needs-alt-core-clk;
qcom,iommu-bfb-regs = <0x204c
0x2050
@@ -188,6 +194,7 @@
&vfe_iommu {
status = "ok";
+ vdd-supply = <&gdsc_vfe>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8226-mtp.dts
rename to arch/arm/boot/dts/msm8226-mtp.dtsi
index 967eb82..ae57797 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -10,20 +10,9 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-/include/ "msm8226.dtsi"
/include/ "dsi-panel-nt35590-720p-video.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
-/ {
- model = "Qualcomm MSM 8226 MTP";
- compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
- qcom,msm-id = <145 8 0>,
- <158 8 0>,
- <159 8 0>,
- <198 8 0>;
-};
-
&soc {
serial@f991f000 {
status = "ok";
@@ -45,7 +34,6 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
- synaptics,reg-en;
};
};
@@ -114,6 +102,21 @@
};
};
+&usb_otg {
+ #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";
+
+ qcom,hsusb-otg-mode = <3>;
+ vbus_otg-supply = <&usb_otg_sw>;
+};
+
&sdcc1 {
vdd-supply = <&pm8226_l17>;
qcom,vdd-always-on;
@@ -303,7 +306,7 @@
qcom,cs-out-en;
qcom,op-fdbck = <1>;
qcom,default-state = "on";
- qcom,max-current = <25>;
+ qcom,max-current = <20>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
@@ -427,9 +430,12 @@
qcom,charging-disabled;
};
+&usb_otg_sw {
+ status = "okay";
+};
+
&slim_msm {
tapan_codec {
qcom,cdc-micbias1-ext-cap;
- qcom,cdc-micbias2-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dtsi
similarity index 96%
rename from arch/arm/boot/dts/msm8226-qrd.dts
rename to arch/arm/boot/dts/msm8226-qrd.dtsi
index f6e8f8b..a60ff26 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -10,20 +10,9 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-/include/ "msm8226.dtsi"
/include/ "dsi-panel-nt35590-720p-video.dtsi"
/include/ "msm8226-camera-sensor-qrd.dtsi"
-/ {
- model = "Qualcomm MSM 8226 QRD";
- compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
- qcom,msm-id = <145 11 0>,
- <158 11 0>,
- <159 11 0>,
- <198 11 0>;
-};
-
&soc {
serial@f991f000 {
status = "ok";
@@ -45,7 +34,6 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
- synaptics,reg-en;
};
};
@@ -111,6 +99,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
};
@@ -306,7 +295,7 @@
qcom,cs-out-en;
qcom,op-fdbck = <1>;
qcom,default-state = "on";
- qcom,max-current = <25>;
+ qcom,max-current = <20>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 6aeaf49..3254d17 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -30,8 +30,9 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
- reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
+ <0xfc4bc450 16>;
+ reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
@@ -223,8 +224,27 @@
regulator-max-microvolt = <1800000>;
qcom,init-voltage = <1800000>;
status = "okay";
+ };
+
+ pm8226_l8_ao: regulator-l8-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l8_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
qcom,consumer-supplies = "vdd_sr2_pll", "";
};
+
+ pm8226_l8_so: regulator-l8-so {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l8_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-enable = <0>;
+ };
};
rpm-regulator-ldoa9 {
@@ -420,3 +440,21 @@
};
};
};
+
+&pm8226_chg_boost {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "8226_smbbp_boost";
+};
+
+&soc {
+ usb_otg_sw: regulator-ncp380 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_sw";
+ gpio = <&msmgpio 67 0>;
+ parent-supply = <&pm8226_chg_boost>;
+ startup-delay-us = <4000>;
+ enable-active-high;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v1-cdp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v1-cdp.dts
index dcf4f92..9c49840 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v1-cdp.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8226-v1.dtsi"
+/include/ "msm8226-cdp.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8226 CDP";
+ compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
+ qcom,msm-id = <145 1 0>,
+ <158 1 0>,
+ <159 1 0>,
+ <198 1 0>,
+ <205 1 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v1-mtp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v1-mtp.dts
index dcf4f92..b1d46b1 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8226-v1.dtsi"
+/include/ "msm8226-mtp.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8226 MTP";
+ compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
+ qcom,msm-id = <145 8 0>,
+ <158 8 0>,
+ <159 8 0>,
+ <198 8 0>,
+ <205 8 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v1-qrd.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v1-qrd.dts
index dcf4f92..d2aabac 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v1-qrd.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8226-v1.dtsi"
+/include/ "msm8226-qrd.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8226 QRD";
+ compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+ qcom,msm-id = <145 11 0>,
+ <158 11 0>,
+ <159 11 0>,
+ <198 11 0>,
+ <205 11 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v1.dtsi
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v1.dtsi
index dcf4f92..d471bec 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v1.dtsi
@@ -10,13 +10,10 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8226.dtsi file.
+ */
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/include/ "msm8226.dtsi"
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v2-cdp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v2-cdp.dts
index dcf4f92..2b18491 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v2-cdp.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8226-v2.dtsi"
+/include/ "msm8226-cdp.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8226v2 CDP";
+ compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
+ qcom,msm-id = <145 1 0x20000>,
+ <158 1 0x20000>,
+ <159 1 0x20000>,
+ <198 1 0x20000>,
+ <205 1 0x20000>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v2-mtp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v2-mtp.dts
index dcf4f92..f15dd4c 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v2-mtp.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8226-v2.dtsi"
+/include/ "msm8226-mtp.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8226v2 MTP";
+ compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
+ qcom,msm-id = <145 8 0x20000>,
+ <158 8 0x20000>,
+ <159 8 0x20000>,
+ <198 8 0x20000>,
+ <205 8 0x20000>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v2-qrd.dts
similarity index 62%
rename from arch/arm/mach-msm/clock-mdss-8226.h
rename to arch/arm/boot/dts/msm8226-v2-qrd.dts
index dcf4f92..1a89d78 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v2-qrd.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8226-v2.dtsi"
+/include/ "msm8226-qrd.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8226v2 QRD";
+ compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
+ qcom,msm-id = <145 11 0x20000>,
+ <158 11 0x20000>,
+ <159 11 0x20000>,
+ <198 11 0x20000>,
+ <205 11 0x20000>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8226-v2.dtsi
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8226-v2.dtsi
index dcf4f92..d471bec 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -10,13 +10,10 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8226.dtsi file.
+ */
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/include/ "msm8226.dtsi"
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 9d51204..7c98104 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -26,7 +26,7 @@
memory {
secure_mem: secure_region {
linux,contiguous-region;
- reg = <0 0x3800000>;
+ reg = <0 0x6D00000>;
label = "secure_mem";
};
@@ -241,7 +241,7 @@
};
};
- usb@f9a55000 {
+ usb_otg: usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>, <0 140 0>;
@@ -259,7 +259,7 @@
qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
- qcom,msm-bus,name = "usb2";
+ qcom,msm-bus,name = "usb";
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
@@ -329,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,8 +547,8 @@
qcom,iris-vdddig-supply = <&pm8226_l24>;
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,has-pronto-hw;
+ qcom,has-autodetect-xo;
};
qcom,msm-adsp-sensors {
@@ -642,6 +642,10 @@
rpm-channel-type = <15>; /* SMD_APPS_RPM */
};
+ qcom,bcl {
+ compatible = "qcom,bcl";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
@@ -843,6 +847,7 @@
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
@@ -1007,6 +1012,12 @@
<55 512 0 0>,
<55 512 3936000 393600>;
};
+
+ cpu-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 7ed914e..d9bb6ab 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -23,6 +23,13 @@
qcom,hw-sel = "NoC";
qcom,rpm-en;
+ coresight-id = <52>;
+ coresight-name = "coresight-mnoc";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <5>;
+
mas-mdp-port0 {
cell-id = <22>;
label = "mas-mdp-port0";
@@ -221,6 +228,13 @@
qcom,hw-sel = "NoC";
qcom,rpm-en;
+ coresight-id = <50>;
+ coresight-name = "coresight-snoc";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <3>;
+
mas-lpass-ahb {
cell-id = <52>;
label = "mas-lpass-ahb";
@@ -422,6 +436,13 @@
qcom,hw-sel = "NoC";
qcom,rpm-en;
+ coresight-id = <54>;
+ coresight-name = "coresight-pnoc";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <6>;
+
mas-pnoc-cfg {
cell-id = <88>;
label = "mas-pnoc-cfg";
@@ -896,6 +917,13 @@
qcom,hw-sel = "BIMC";
qcom,rpm-en;
+ coresight-id = <55>;
+ coresight-name = "coresight-bimc";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <3>;
+
mas-ampss-m0 {
cell-id = <1>;
label = "mas-ampss-m0";
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 257a41c..bbdc2b8 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -132,6 +132,16 @@
debounce-interval = <15>;
};
};
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2";
+ };
};
&i2c_cdc {
@@ -192,6 +202,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x60>;
+ qcom,mode = "manual";
};
};
@@ -206,6 +217,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x10>;
+ qcom,mode = "manual";
};
};
};
@@ -325,6 +337,12 @@
};
mpp@a300 { /* MPP 4 */
+ /* PA_THERM config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
};
};
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index d1b30ee..7e3ee0d 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -25,7 +25,6 @@
qcom,initial-pwrlevel = <1>;
qcom,idle-timeout = <8>; /* <HZ/12> */
- qcom,nap-allowed = <1>;
qcom,strtstp-sleepwake;
qcom,clk-map = <0x000005E>; /* KGSL_CLK_CORE |
KGSL_CLK_IFACE | KGSL_CLK_MEM | KGSL_CLK_MEM_IFACE |
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index abd4228..9406a09 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -132,6 +132,16 @@
debounce-interval = <15>;
};
};
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS Internal2";
+ };
};
&i2c_cdc {
@@ -192,6 +202,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x60>;
+ qcom,mode = "manual";
};
};
@@ -206,6 +217,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x10>;
+ qcom,mode = "manual";
};
};
};
@@ -328,6 +340,12 @@
};
mpp@a300 { /* MPP 4 */
+ /* PA_THERM config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
};
};
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index 61eba7f..5f9365a 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -23,6 +23,35 @@
};
&soc {
+ i2c@f9923000{
+ focaltech@38{
+ compatible = "focaltech,5x06";
+ reg = <0x38>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ focaltech,family-id = <0x06>;
+ focaltech,reset-gpio = <&msmgpio 0 0x00>;
+ focaltech,irq-gpio = <&msmgpio 1 0x00>;
+ focaltech,display-coords = <0 0 480 800>;
+ focaltech,panel-coords = <0 0 480 800>;
+ focaltech,button-map= <139 102 158>;
+ focaltech,no-force-update;
+ focaltech,i2c-pull-up;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "ft5x06_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <481>;
+ qcom,panel-maxy = <940>;
+ qcom,key-codes = <139 0 102 158 0 0 0>;
+ qcom,y-offset = <0>;
+ };
serial@f991e000 {
status = "ok";
};
@@ -103,6 +132,16 @@
reg = <0x55>;
};
};
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS Internal1", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "AMIC1", "MIC BIAS Internal1",
+ "AMIC2", "MIC BIAS Internal2";
+ };
};
&spmi_bus {
@@ -205,7 +244,6 @@
&pm8110_chg {
status = "ok";
- qcom,charging-disabled;
qcom,chgr@1000 {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index a90f053..09520c5 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -30,8 +30,9 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
- reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
+ <0xfc4bc450 16>;
+ reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
@@ -232,8 +233,27 @@
regulator-max-microvolt = <1800000>;
qcom,init-voltage = <1800000>;
status = "okay";
+ };
+
+ pm8110_l10_ao: regulator-l10-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8110_l10_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
qcom,consumer-supplies = "vdd_sr2_pll", "";
};
+
+ pm8110_l10_so: regulator-l10-so {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8110_l10_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-enable = <0>;
+ };
};
rpm-regulator-ldoa12 {
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 689392c..f5a19fe 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -28,6 +28,7 @@
aliases {
sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ spi4 = &spi_4;
};
soc: soc { };
@@ -500,6 +501,29 @@
qcom,i2c-bus-freq = <100000>;
};
+ spi_4: spi@f9926000 { /* BLSP1 QUP4 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9926000 0x1000>,
+ <0xf9904000 0x15000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 98 0>, <0 238 0>;
+ spi-max-frequency = <50000000>;
+
+ gpios = <&msmgpio 89 0>, /* CLK */
+ <&msmgpio 87 0>, /* MISO */
+ <&msmgpio 86 0>; /* MOSI */
+ cs-gpios = <&msmgpio 88 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <18>;
+ qcom,bam-producer-pipe-index = <19>;
+ };
+
qcom,pronto@fb21b000 {
compatible = "qcom,pil-pronto";
reg = <0xfb21b000 0x3000>,
@@ -668,7 +692,8 @@
qcom,iris-vdddig-supply = <&pm8110_l5>;
gpios = <&msmgpio 23 0>, <&msmgpio 24 0>, <&msmgpio 25 0>, <&msmgpio 26 0>, <&msmgpio 27 0>;
- qcom,has_pronto_hw;
+ qcom,has-pronto-hw;
+ qcom,wlan-rx-buff-count = <256>;
};
qcom,mss@fc880000 {
@@ -694,6 +719,7 @@
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
@@ -979,6 +1005,67 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
+
+ chan@13 {
+ label = "pa_therm0";
+ reg = <0x13>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
};
+&pm8110_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@13 {
+ label = "pa_therm0";
+ reg = <0x13>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-cdp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-cdp.dts
index dcf4f92..7a91d40 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-cdp.dts
@@ -10,13 +10,13 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-cdp.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926 CDP";
+ compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
+ qcom,msm-id = <200 1 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-mtp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-mtp.dts
index dcf4f92..fea925d 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-mtp.dts
@@ -10,13 +10,13 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-mtp.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926 MTP";
+ compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
+ qcom,msm-id = <200 8 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-qrd.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-qrd.dts
index dcf4f92..e056b7e 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-qrd.dts
@@ -10,13 +10,12 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926 QRD";
+ compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+ qcom,msm-id = <200 11 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926.dtsi
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926.dtsi
index dcf4f92..6f3f592 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -10,13 +10,21 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/*
+ * Only 8926-specific property overrides should be placed inside this
+ * file. Device definitions should be placed inside the msm8226.dtsi
+ * file.
+ */
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "msm8226.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
+/ {
+ model = "Qualcomm MSM 8926";
+ compatible = "qcom,msm8926";
+};
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+&soc {
+ qcom,mss@fc880000 {
+ vdd_mss-supply = <&pm8226_s5>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index bfe955e..609a1b3 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1151,7 +1151,7 @@
qcom,fabclk-dual = "mem_clk";
qcom,fabclk-active = "mem_a_clk";
qcom,ntieredslaves = <0>;
- qcom,qos-freq = <4800>;
+ qcom,qos-freq = <19200>;
qcom,hw-sel = "BIMC";
qcom,rpm-en;
@@ -1168,12 +1168,18 @@
qcom,masterp = <0>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Fixed";
+ qcom,mode = "Limiter";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
+ qcom,mode-thresh = "Fixed";
+ qcom,thresh = <2000000>;
+ qcom,dual-conf;
+ qcom,bimc,bw = <300000>;
+ qcom,bimc,gp = <5>;
+ qcom,bimc,thmp = <50>;
};
mas-ampss-m1 {
@@ -1182,12 +1188,18 @@
qcom,masterp = <1>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Fixed";
+ qcom,mode = "Limiter";
qcom,qport = <1>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
+ qcom,mode-thresh = "Fixed";
+ qcom,thresh = <2000000>;
+ qcom,dual-conf;
+ qcom,bimc,bw = <300000>;
+ qcom,bimc,gp = <5>;
+ qcom,bimc,thmp = <50>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
new file mode 100644
index 0000000..e84a47d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -0,0 +1,174 @@
+/*
+ * 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
+ * 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.
+ */
+
+&cci {
+
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ actuator1: qcom,actuator@36 {
+ cell-index = <1>;
+ reg = <0x36>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6e {
+ compatible = "qcom,s5k3l1yx";
+ reg = <0x6e 0x0>;
+ qcom,slave-id = <0x6e 0x0 0x3121>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,sensor-name = "s5k3l1yx";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 30000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@20 {
+ compatible = "qcom,imx135";
+ reg = <0x20>;
+ qcom,slave-id = <0x20 0x0016 0x0135>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "imx135";
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 30000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@6c {
+ compatible = "qcom,ov2720";
+ reg = <0x6c 0x0>;
+ qcom,slave-id = <0x6c 0x300A 0x2720>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <180>;
+ qcom,sensor-name = "ov2720";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 17 0>,
+ <&msmgpio 18 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ 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 = <0x4320>;
+ qcom,csi-lane-mask = <0x7>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 94 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ 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 = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index e0b572e..cf968d2 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -35,6 +35,7 @@
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
+ qcom,actuator-src = <&actuator0>;
qcom,sensor-name = "s5k3l1yx";
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
@@ -50,12 +51,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ 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_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 3e65b8a..2a60df4 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -599,6 +599,13 @@
};
gpio@e300 { /* GPIO 36 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <3>; /* QPNP_PIN_SEL_FUNC_2 */
+ qcom,master-en = <1>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 5172a5a..06b9c18 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -26,7 +26,6 @@
qcom,step-pwrlevel = <2>;
qcom,idle-timeout = <8>; //<HZ/12>
- qcom,nap-allowed = <1>;
qcom,strtstp-sleepwake;
qcom,clk-map = <0x0000006>; //KGSL_CLK_CORE | KGSL_CLK_IFACE
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index b30d65c..2dc52b6 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -208,7 +208,7 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 19 01 00 0D 02 0D 00 00 00 00
+ 19 03 00 1E 05 0D 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
@@ -221,8 +221,8 @@
41 00 14 14 00 00 00 01 00 00
/* Object 9, Instance = 0 */
8F 00 00 20 34 00 87 4B 02 03
- 00 05 03 40 0A 14 14 0A 80 07
- 38 04 03 03 03 03 08 28 02 3C
+ 00 05 03 41 0A 14 14 0A 80 07
+ 38 04 00 00 03 03 08 28 02 3C
0F 0F 2E 33 01 00
/* Object 15, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
@@ -406,6 +406,29 @@
<85 512 40000 160000>;
};
};
+
+ wlan0: qca,wlan {
+ compatible = "qca,ar6004-hsic";
+ qcom,msm-bus,name = "wlan";
+ qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
+ qca,wifi-vddpa-supply = <&pm8941_l19>;
+ qca,wifi-vddio-supply = <&pm8941_l10>;
+ qcom,msm-bus,num-cases = <5>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <85 512 0 0>,
+ <85 512 40000 160000>,
+ <85 512 40000 320000>,
+ <85 512 40000 480000>,
+ <85 512 40000 800000>;
+ };
+
+ wlan_sdio:qca,wlan_sdio {
+ compatible = "qca,ar6004-sdio";
+ qcom,msm-bus,name = "wlan_sdio";
+ qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
+ };
};
&mdss_fb0 {
diff --git a/arch/arm/boot/dts/msm8974-v1-iommu.dtsi b/arch/arm/boot/dts/msm8974-v1-iommu.dtsi
index c6693e1..56369dc 100644
--- a/arch/arm/boot/dts/msm8974-v1-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-iommu.dtsi
@@ -14,20 +14,27 @@
&jpeg_iommu {
status = "ok";
+ vdd-supply = <&gdsc_jpeg>;
};
&mdp_iommu {
status = "ok";
+ vdd-supply = <&gdsc_mdss>;
};
&venus_iommu {
status = "ok";
+ vdd-supply = <&gdsc_venus>;
};
&kgsl_iommu {
status = "ok";
+ qcom,needs-alt-core-clk;
+ vdd-supply = <&gdsc_oxili_cx>;
+ qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
};
&vfe_iommu {
status = "ok";
+ vdd-supply = <&gdsc_vfe>;
};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index b5652d1..03f7e80 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -14,6 +14,7 @@
&venus_iommu {
status = "ok";
+ vdd-supply = <&gdsc_venus>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
@@ -78,7 +79,7 @@
venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8f000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x85>;
label = "venus_sec_pixel";
qcom,secure-context;
@@ -87,7 +88,7 @@
venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc90000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x87 0xA0>;
label = "venus_sec_non_pixel";
qcom,secure-context;
@@ -96,6 +97,7 @@
&jpeg_iommu {
status = "ok";
+ vdd-supply = <&gdsc_jpeg>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
@@ -133,6 +135,7 @@
&mdp_iommu {
status = "ok";
+ vdd-supply = <&gdsc_mdss>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
@@ -176,7 +179,10 @@
&kgsl_iommu {
status = "ok";
+ vdd-supply = <&gdsc_oxili_cx>;
+ qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
qcom,iommu-enable-halt;
+ qcom,needs-alt-core-clk;
qcom,iommu-bfb-regs = <0x204c
0x2050
@@ -207,6 +213,7 @@
&vfe_iommu {
status = "ok";
+ vdd-supply = <&gdsc_vfe>;
qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 63a31dc..96e78ac 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -106,21 +106,21 @@
<3456000 2076000>,
<3662000 2198000>;
qcom,enc-ddr-ab-ib = <0 0>,
- <60000 302000>,
- <182000 302000>,
- <402000 302000>,
- <804000 604000>,
- <1288000 967000>,
- <2340000 1404000>,
- <24940000 1496000>;
+ <120000 302000>,
+ <364000 302000>,
+ <804000 302000>,
+ <1608000 604000>,
+ <2576000 967000>,
+ <4680000 1404000>,
+ <49880000 1496000>;
qcom,dec-ddr-ab-ib = <0 0>,
- <104000 303000>,
- <268000 303000>,
- <506000 303000>,
- <1012000 606000>,
- <1620000 970000>,
- <2024000 1212000>,
- <2132000 1279000>;
+ <208000 303000>,
+ <536000 303000>,
+ <1012000 303000>,
+ <2024000 606000>,
+ <3240000 970000>,
+ <4048000 1212000>,
+ <4264000 1279000>;
qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
&venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 4367807..5ae8808 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -64,7 +64,7 @@
adsp_mem: adsp_region {
linux,contiguous-region;
- reg = <0 0x2000000>;
+ reg = <0 0x2F00000>;
label = "adsp_mem";
};
@@ -237,8 +237,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <84 512 0 0>,
- <84 512 500 800>;
+ <86 512 0 0>,
+ <86 512 500 800>;
};
usb_otg: usb@f9a55000 {
@@ -629,6 +629,14 @@
"tsif_data",
"tsif_sync";
qcom,gpios-func = <1>;
+
+ qcom,msm-bus,name = "tsif";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <82 512 0 0>, /* No vote */
+ <82 512 12288 24576>; /* Max. bandwidth, 2xTSIF, each max of 96Mbps */
};
slim_msm: slim@fe12f000 {
@@ -645,7 +653,9 @@
elemental-addr = [00 01 A0 00 17 02];
interrupt-parent = <&wcd9xxx_intc>;
- interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30>;
qcom,cdc-reset-gpio = <&msmgpio 63 0>;
@@ -1167,6 +1177,7 @@
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
@@ -1213,8 +1224,8 @@
qcom,iris-vdddig-supply = <&pm8941_l3>;
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
- qcom,has_48mhz_xo;
- qcom,has_pronto_hw;
+ qcom,has-48mhz-xo;
+ qcom,has-pronto-hw;
};
qcom,ocmem@fdd00000 {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 1d10f8c..673b640 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -237,40 +237,40 @@
<0xff 240>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
- qcom,gpio-map = <4 1>,
- <5 5>,
- <6 9>,
- <7 18>,
- <8 20>,
- <9 24>,
- <10 27>,
- <11 28>,
- <12 34>,
- <13 35>,
- <14 37>,
- <15 42>,
- <16 44>,
- <17 46>,
- <18 50>,
- <19 54>,
- <20 59>,
- <21 61>,
- <22 62>,
- <23 64>,
- <24 65>,
- <25 66>,
- <26 67>,
- <27 68>,
- <28 71>,
- <29 72>,
- <30 73>,
- <31 74>,
- <32 75>,
- <33 77>,
- <34 79>,
- <35 80>,
- <36 82>,
- <37 86>;
+ qcom,gpio-map = <4 0>,
+ <5 1>,
+ <6 2>,
+ <7 3>,
+ <8 4>,
+ <9 5>,
+ <10 6>,
+ <11 7>,
+ <12 8>,
+ <13 9>,
+ <14 10>,
+ <15 11>,
+ <16 12>,
+ <17 13>,
+ <18 14>,
+ <19 15>,
+ <20 16>,
+ <21 17>,
+ <22 18>,
+ <23 19>,
+ <24 20>,
+ <25 21>,
+ <26 24>,
+ <27 25>,
+ <28 51>,
+ <29 61>,
+ <30 62>,
+ <31 63>,
+ <32 64>,
+ <33 65>,
+ <34 66>,
+ <35 67>,
+ <36 69>,
+ <37 71>;
};
qcom,pm-8x60 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index bb1ea3d..f654545 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -165,6 +165,7 @@
qcom,hsusb-otg-lpm-on-dev-suspend;
qcom,hsusb-otg-clk-always-on-workaround;
qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect;
+ qcom,hsusb-otg-delay-lpm;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -191,6 +192,7 @@
qcom,pool-64-bit-align;
qcom,enable-hbm;
hsic,consider-ipa-handshake;
+ qcom,ahb-async-bridge-bypass;
};
qcom,usbbam@f9a44000 {
@@ -255,8 +257,8 @@
qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <3>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe4 {
@@ -268,8 +270,8 @@
qcom,usb-bam-mem-type = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <4>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe5 {
@@ -281,8 +283,8 @@
qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <5>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe6 {
@@ -294,8 +296,8 @@
qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <6>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe7 {
@@ -770,6 +772,7 @@
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msmsamarium-rumi.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msmsamarium-rumi.dts
index dcf4f92..9a679a4 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msmsamarium-rumi.dts
@@ -10,13 +10,16 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "msmsamarium.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
+/ {
+ model = "Qualcomm MSM SAMARIUM RUMI";
+ compatible = "qcom,msmsamarium-rumi", "qcom,msmsamarium", "qcom,rumi";
+ qcom,msm-id = <195 0 0>;
+};
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+&uartblsp0dm2{
+ status = "ok";
+};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 549bc73..a004835 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -353,8 +353,9 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_IOMMU_NON_SECURE=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
index c06161d..5d05596 100644
--- a/arch/arm/configs/mpq8092_defconfig
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -50,6 +50,7 @@
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_RUN_QUEUE_STATS=y
CONFIG_MSM_SPM_V2=y
@@ -331,7 +332,7 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index ba36df1..431ac58 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -278,7 +278,28 @@
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_OV7692=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_TAVARUA=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index b903a0b..c635e4b 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -280,7 +280,28 @@
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_OV7692=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_TAVARUA=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
new file mode 100644
index 0000000..d58f7fb
--- /dev/null
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -0,0 +1,424 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO 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_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=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_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8226=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_BAM_DMUX=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_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_USB_USBNET=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=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_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_WFD=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CSVT=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_MSM_IOMMU_V1=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_EVENT=m
+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_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+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_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPPOE=y
+CONFIG_N_HDLC=y
+CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 7bf54ce..07378b2 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -21,6 +21,7 @@
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
@@ -78,6 +79,9 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_USE_OF=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -200,19 +204,24 @@
CONFIG_CMA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
@@ -233,7 +242,6 @@
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
CONFIG_SPMI=y
-CONFIG_MSM_BUS_SCALING=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
CONFIG_SLIMBUS_MSM_NGD=y
@@ -242,14 +250,17 @@
CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_BMS=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_WCD9306_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_MEDIA_SUPPORT=y
@@ -268,10 +279,32 @@
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
CONFIG_MSMB_JPEG=y
-CONFIG_SWITCH=y
-CONFIG_MSM_WFD=y
CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_WFD=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
@@ -289,12 +322,35 @@
# CONFIG_BACKLIGHT_GENERIC is not set
CONFIG_SOUND=y
CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=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=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CSVT=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
@@ -315,6 +371,7 @@
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_SWITCH=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
@@ -331,7 +388,8 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
-CONFIG_MSM_IOMMU=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_MSM_IOMMU_V1=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
@@ -377,11 +435,15 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_CCITT=y
-CONFIG_QPNP_VIBRATOR=y
-CONFIG_QSEECOM=y
-CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
-CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPPOE=y
+CONFIG_N_HDLC=y
+CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 368078e..3bbff5c 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -34,6 +34,7 @@
CONFIG_MODVERSIONS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8610=y
CONFIG_ARCH_MSM8226=y
@@ -61,8 +62,6 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
-CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
@@ -72,6 +71,8 @@
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -81,6 +82,9 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_USE_OF=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -203,11 +207,13 @@
CONFIG_CMA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -237,7 +243,6 @@
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
CONFIG_SPMI=y
-CONFIG_MSM_BUS_SCALING=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
CONFIG_SLIMBUS_MSM_NGD=y
@@ -246,12 +251,14 @@
CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_BMS=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_WCD9306_CODEC=y
CONFIG_REGULATOR_STUB=y
@@ -269,12 +276,12 @@
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
+# CONFIG_MSM_ISPIF_V1 is not set
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
CONFIG_MSMB_JPEG=y
-CONFIG_SWITCH=y
-CONFIG_MSM_WFD=y
CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_WFD=y
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_IRIS=y
@@ -282,6 +289,7 @@
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
@@ -300,7 +308,6 @@
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
@@ -322,6 +329,7 @@
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_SWITCH=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
@@ -338,7 +346,8 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
-CONFIG_MSM_IOMMU=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_MSM_IOMMU_V0=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -357,7 +366,6 @@
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
-CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
@@ -365,6 +373,3 @@
CONFIG_CRYPTO_TWOFISH=y
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
-CONFIG_QPNP_VIBRATOR=y
-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 7bb3629..d11773f 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -32,6 +32,7 @@
CONFIG_MODVERSIONS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8610=y
CONFIG_ARCH_MSM8226=y
@@ -79,6 +80,9 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_USE_OF=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -201,11 +205,13 @@
CONFIG_CMA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
+CONFIG_QSEECOM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -235,7 +241,6 @@
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
CONFIG_SPMI=y
-CONFIG_MSM_BUS_SCALING=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
CONFIG_SLIMBUS_MSM_NGD=y
@@ -244,12 +249,14 @@
CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_BMS=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_WCD9306_CODEC=y
CONFIG_REGULATOR_STUB=y
@@ -261,18 +268,41 @@
# CONFIG_MSM_CAMERA is not set
CONFIG_OV8825=y
CONFIG_MSM_CAMERA_SENSOR=y
-CONFIG_MSM_CPP=y
+# CONFIG_MSM_CPP is not set
CONFIG_MSM_CCI=y
-CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSI22_HEADER=y
+CONFIG_MSM_CSI20_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
+# CONFIG_MSM_ISPIF_V1 is not set
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
CONFIG_MSMB_JPEG=y
-CONFIG_SWITCH=y
-CONFIG_MSM_WFD=y
CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_WFD=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_IRIS=y
@@ -280,6 +310,7 @@
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
CONFIG_FB=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
@@ -297,7 +328,6 @@
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
@@ -319,6 +349,7 @@
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_SWITCH=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
@@ -335,7 +366,8 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
-CONFIG_MSM_IOMMU=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_MSM_IOMMU_V0=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
@@ -381,12 +413,7 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_CCITT=y
-CONFIG_QPNP_VIBRATOR=y
-CONFIG_QSEECOM=y
-CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_IOSCHED_TEST=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 5885c6e..1b465af 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -314,7 +314,28 @@
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_GEMINI=y
CONFIG_OV7692=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index abc7460..40fde84 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -314,7 +314,28 @@
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_GEMINI=y
CONFIG_OV7692=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 6c18a97..aefc7c9 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -95,6 +95,8 @@
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_DCVS=y
CONFIG_MSM_HSIC_SYSMON=y
+CONFIG_WALL_CLK=m
+CONFIG_WALL_CLK_SYSFS=m
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
@@ -378,7 +380,28 @@
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_VIDEO=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_USB_VIDEO_CLASS=y
@@ -482,7 +505,7 @@
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_MSM_AVTIMER=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_V0=y
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index f699dee..fbad97a 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -382,7 +382,28 @@
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_VIDEO=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_USB_VIDEO_CLASS=y
@@ -484,7 +505,7 @@
CONFIG_MSM_SSBI=y
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_BAMDMA=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_V0=y
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 72032dc..6c12216 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -329,12 +329,12 @@
CONFIG_OV2720=y
CONFIG_IMX135=y
CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
CONFIG_MSM_CPP=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
-CONFIG_MSM_EEPROM=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
CONFIG_MSMB_CAMERA=y
@@ -368,10 +368,12 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
@@ -439,7 +441,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_QPNP_REVID=y
CONFIG_QPNP_COINCELL=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
@@ -458,8 +460,8 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_TIMER_STATS=y
CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
@@ -476,4 +478,3 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
-CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 091cdd9..967f62d 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -335,12 +335,12 @@
CONFIG_OV2720=y
CONFIG_IMX135=y
CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
CONFIG_MSM_CPP=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
-CONFIG_MSM_EEPROM=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
CONFIG_MSMB_CAMERA=y
@@ -374,10 +374,12 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
@@ -445,9 +447,9 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_QPNP_REVID=y
CONFIG_QPNP_COINCELL=y
-CONFIG_MSM_IOMMU=y
-CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_V1=y
CONFIG_MSM_IOMMU_PMON=y
+CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
CONFIG_CORESIGHT=y
@@ -508,4 +510,3 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
-CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 0fb8538..3b84f8f 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -159,7 +159,6 @@
CONFIG_MTD_BLOCK=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-# CONFIG_ANDROID_PMEM is not set
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index c48eb79..3f15a68 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -54,9 +54,9 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_RTB=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_NO_HZ=y
@@ -161,15 +161,14 @@
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_CHAR=y
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-# CONFIG_ANDROID_PMEM is not set
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -227,6 +226,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_MONITOR=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 4f2a637..c771bc4 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -53,9 +53,9 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_RTB=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_NO_HZ=y
@@ -163,15 +163,14 @@
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_CHAR=y
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-# CONFIG_ANDROID_PMEM is not set
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -230,6 +229,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_MONITOR=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -324,8 +324,5 @@
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEFLATE=y
-#CONFIG_CRYPTO_DEV_QCRYPTO is not set
-#CONFIG_CRYPTO_DEV_QCE is not set
-#CONFIG_CRYPTO_DEV_QCEDEV is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 5a85f14..71f4827 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -23,6 +23,7 @@
extern void disable_hlt(void);
extern void enable_hlt(void);
+extern int get_hlt(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index bee7f9d..24bc80b 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -26,6 +26,18 @@
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
+#ifndef CONFIG_ARM_LPAE
+ if (base > ((phys_addr_t)~0)) {
+ pr_crit("Ignoring memory at 0x%08llx due to lack of LPAE support\n",
+ base);
+ return;
+ }
+
+ if (size > ((phys_addr_t)~0))
+ size = ((phys_addr_t)~0);
+
+ /* arm_add_memory() already checks for the case of base + size > 4GB */
+#endif
arm_add_memory(base, size);
}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index c440f47..6e94b32 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -742,6 +742,7 @@
static struct of_device_id armpmu_of_device_ids[] = {
{.compatible = "arm,cortex-a9-pmu"},
{.compatible = "arm,cortex-a8-pmu"},
+ {.compatible = "arm,cortex-a7-pmu"},
{.compatible = "arm,cortex-a5-pmu"},
{.compatible = "arm,arm1136-pmu"},
{.compatible = "arm,arm1176-pmu"},
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index e7a9237..fe97ff2 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -86,6 +86,12 @@
EXPORT_SYMBOL(enable_hlt);
+int get_hlt(void)
+{
+ return hlt_counter;
+}
+EXPORT_SYMBOL(get_hlt);
+
static int __init nohlt_setup(char *__unused)
{
hlt_counter = 1;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6b62269..7824502 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -404,6 +404,7 @@
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
+ select CPU_FREQ_MSM
select MSM_MULTIMEDIA_USE_ION
select MSM_RPM_STATS_LOG
select MSM_QDSP6_APRV2
@@ -457,9 +458,6 @@
select MSM_BUS_SCALING
select CPU_FREQ_MSM
select CPU_FREQ
- select CPU_FREQ_GOV_USERSPACE
- select CPU_FREQ_GOV_ONDEMAND
- select CPU_FREQ_GOV_POWERSAVE
select MSM_PIL
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
@@ -499,8 +497,6 @@
select MSM_BUS_SCALING
select CPU_FREQ_MSM
select CPU_FREQ
- select CPU_FREQ_GOV_USERSPACE
- select CPU_FREQ_GOV_ONDEMAND
select MSM_PIL
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
@@ -3024,4 +3020,21 @@
suggestions in efuse as initial settings. It converts corner vote
to voltage value before writing to a voltage regulator API, such as
that provided by spm-regulator driver.
+
+config WALL_CLK
+ tristate "Wall Clock hardware block simulation"
+ depends on ARCH_APQ8064
+ help
+ This driver simulates the wall-clock hardware block on fsm8064_ep
+ femto emulation platform. This block will be used to provide
+ clock information to the LTE Layer 2 module running on the hexagon
+ processor.
+
+config WALL_CLK_SYSFS
+ tristate "Wall Clock SysFS Support"
+ depends on SYSFS && WALL_CLK
+ help
+ Support the wallclk directory in sysfs filesystem to enable the
+ wall clock simulation and read the current SFN.
+
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fa3344d..9a34d87 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -111,31 +111,15 @@
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
endif
obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MSM8226
-ifndef CONFIG_ARCH_MSM9625
-ifndef CONFIG_ARCH_MPQ8092
-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
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
+obj-$(CONFIG_ARCH_MSM7X01A) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X25) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X30) += nand_partitions.o
+obj-$(CONFIG_ARCH_QSD8X50) += nand_partitions.o
+obj-$(CONFIG_ARCH_FSM9XXX) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM9615) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM8625) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27A) += nand_partitions.o
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -310,6 +294,7 @@
obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
+obj-$(CONFIG_ARCH_MPQ8092) += 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
@@ -319,7 +304,7 @@
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) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
@@ -439,3 +424,6 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
+
+obj-$(CONFIG_WALL_CLK) += wallclk.o
+obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b40c70a..3469c66 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -84,9 +84,17 @@
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-xpm.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-mtp.dtb
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
@@ -109,3 +117,4 @@
# MSMSAMARIUM
zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000
dtb-$(CONFIG_ARCH_MSMSAMARIUM) += msmsamarium-sim.dtb
+ dtb-$(CONFIG_ARCH_MSMSAMARIUM) += msmsamarium-rumi.dtb
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 5793326..733c7a8 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -66,7 +66,7 @@
*/
static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
{ 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 7 },
{ 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
@@ -77,7 +77,7 @@
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
- { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 3 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 3 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
{ 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 4 },
{ 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 0c80a56..afa6909 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -160,7 +160,8 @@
static int set_speed(struct clkctl_acpu_speed *tgt_s)
{
int rc = 0;
- unsigned int tgt_freq_hz = tgt_s->khz * 1000;
+ unsigned int div = tgt_s->src_div ? tgt_s->src_div : 1;
+ unsigned int tgt_freq_hz = tgt_s->khz * 1000 * div;
struct clkctl_acpu_speed *strt_s = priv->current_speed;
struct clkctl_acpu_speed *cxo_s = &priv->freq_tbl[0];
struct clk *strt = priv->src_clocks[strt_s->src].clk;
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index bed794b..b5a7552 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1576,8 +1576,14 @@
static int ssrestart_check(void)
{
- DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
+ int ret = 0;
+
+ DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled for SSR\n",
+ __func__);
in_global_reset = 1;
+ ret = subsystem_restart("modem");
+ if (ret == -ENODEV)
+ panic("modem subsystem restart failed\n");
return 1;
}
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 6b15883..bb0a6cc 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -255,7 +255,6 @@
.num_levels = 5,
.set_grp_async = NULL,
.idle_timeout = HZ/10,
- .nap_allowed = true,
.strtstp_sleepwake = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 5ab4a53..b2dcd7a 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -478,6 +478,10 @@
.high_ocv_correction_limit_uv = 50,
.low_ocv_correction_limit_uv = 100,
.hold_soc_est = 3,
+ .enable_fcc_learning = 1,
+ .min_fcc_learning_soc = 20,
+ .min_fcc_ocv_pc = 30,
+ .max_fcc_learning_samples = 5,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 372f8ba..f5a9070 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -89,6 +89,7 @@
#define MHL_GPIO_INT 30
#define MHL_GPIO_RESET 35
+#include "sysmon.h"
#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x4CF000
@@ -1901,6 +1902,8 @@
.peripheral_platform_device = &apq8064_device_hsic_host,
.ramdump_timeout_ms = 120000,
.mdm2ap_status_gpio_run_cfg = &mdm2ap_status_gpio_run_cfg,
+ .sysmon_subsys_id_valid = 1,
+ .sysmon_subsys_id = SYSMON_SS_EXT_MODEM,
};
static struct tsens_platform_data apq_tsens_pdata = {
diff --git a/arch/arm/mach-msm/board-8084-gpiomux.c b/arch/arm/mach-msm/board-8084-gpiomux.c
index 8d5bb49..27f2e0d 100644
--- a/arch/arm/mach-msm/board-8084-gpiomux.c
+++ b/arch/arm/mach-msm/board-8084-gpiomux.c
@@ -17,6 +17,27 @@
#include <mach/board.h>
#include <mach/gpiomux.h>
+static struct gpiomux_setting gpio_i2c_config = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+ {
+ .gpio = 10, /* BLSP1 QUP3 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 11, /* BLSP1 QUP3 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+};
+
void __init apq8084_init_gpiomux(void)
{
int rc;
@@ -26,4 +47,6 @@
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-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index ad4a516..378edc8 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -16,6 +16,7 @@
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
#define KS8851_IRQ_GPIO 115
@@ -440,6 +441,21 @@
},
};
+static struct gpiomux_setting usb_otg_sw_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config usb_otg_sw_configs[] __initdata = {
+ {
+ .gpio = 67,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &usb_otg_sw_cfg,
+ },
+ },
+};
+
void __init msm8226_init_gpiomux(void)
{
int rc;
@@ -468,4 +484,8 @@
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
msm_gpiomux_install(msm_auxpcm_configs,
ARRAY_SIZE(msm_auxpcm_configs));
+
+ if (of_board_is_cdp() || of_board_is_mtp() || of_board_is_xpm())
+ msm_gpiomux_install(usb_otg_sw_configs,
+ ARRAY_SIZE(usb_otg_sw_configs));
}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 521898e..4645d34 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -135,6 +135,8 @@
static const char *msm8226_dt_match[] __initconst = {
"qcom,msm8226",
+ "qcom,msm8926",
+ "qcom,apq8026",
NULL
};
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 593e2b1..7096f3f 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -17,6 +17,12 @@
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -161,6 +167,30 @@
[GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
},
},
+ {
+ .gpio = 86, /* BLSP1 QUP4 SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 87, /* BLSP1 QUP4 SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 89, /* BLSP1 QUP4 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 88, /* BLSP1 QUP4 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
};
static struct msm_gpiomux_config wcnss_5wire_interface[] = {
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 0c6a271..12a6ab1 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -145,7 +145,6 @@
.num_levels = 4,
.set_grp_async = NULL,
.idle_timeout = HZ/12,
- .nap_allowed = true,
.strtstp_sleepwake = false,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index ef65613..d7e678e 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -481,6 +481,10 @@
.high_ocv_correction_limit_uv = 50,
.low_ocv_correction_limit_uv = 100,
.hold_soc_est = 3,
+ .enable_fcc_learning = 1,
+ .min_fcc_learning_soc = 20,
+ .min_fcc_ocv_pc = 30,
+ .max_fcc_learning_samples = 5,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c87d966..8e758bf 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -438,6 +438,10 @@
.high_ocv_correction_limit_uv = 50,
.low_ocv_correction_limit_uv = 100,
.hold_soc_est = 3,
+ .enable_fcc_learning = 1,
+ .min_fcc_learning_soc = 20,
+ .min_fcc_ocv_pc = 30,
+ .max_fcc_learning_samples = 5,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/arch/arm/mach-msm/board-fsm9900.c b/arch/arm/mach-msm/board-fsm9900.c
index 7177355..6e85ece 100644
--- a/arch/arm/mach-msm/board-fsm9900.c
+++ b/arch/arm/mach-msm/board-fsm9900.c
@@ -44,6 +44,22 @@
CLK_DUMMY("iface_clk", BLSP2_UART_CLK, "f9960000.serial", OFF),
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", BLSP2_I2C_CLK, "f9966000.i2c", OFF),
+ CLK_DUMMY("iface_clk", BLSP2_I2C_CLK, "f9966000.i2c", OFF),
+ CLK_DUMMY("core_clk", BLSP1_I2C_CLK, "f9924000.i2c", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_I2C_CLK, "f9924000.i2c", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("phy_clk", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("xo", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("core_clk", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("iface_clk", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("sleep_clk", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("xo", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9824900.sdhci_msm", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9824900.sdhci_msm", OFF),
+ CLK_DUMMY("core_clk", NULL, "f98a4900.sdhci_msm", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f98a4900.sdhci_msm", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index 7b7b7cd..ff7c8e0 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -41,6 +41,10 @@
.size = ARRAY_SIZE(msm_clocks_dummy),
};
+static struct of_dev_auxdata msmkrypton_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
@@ -64,7 +68,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msmkrypton_init_gpiomux();
- board_dt_populate(adata);
+ board_dt_populate(msmkrypton_auxdata_lookup);
msmkrypton_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 00d63a3..a656cee 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -34,6 +34,10 @@
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),
+ 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),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -42,6 +46,10 @@
};
static struct of_dev_auxdata msmsamarium_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+ "msm_sdcc.1", NULL),
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+ "msm_sdcc.2", NULL),
{},
};
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index b7f9fd7..bec9f1b4 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -49,6 +49,8 @@
CLK_DUMMY("sleep_a_clk", NULL, "f9200000.qcom,ssusb", OFF),
CLK_DUMMY("utmi_clk", NULL, "f9200000.qcom,ssusb", OFF),
CLK_DUMMY("ref_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
+ CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, "msm_sps", OFF),
CLK_DUMMY("", ufs_axi_clk_src.c, "", OFF),
CLK_DUMMY("", usb30_master_clk_src.c, "", OFF),
CLK_DUMMY("", usb30_sec_master_clk_src.c, "", OFF),
@@ -73,12 +75,13 @@
CLK_DUMMY("", usb_hsic_system_clk_src.c, "", OFF),
CLK_DUMMY("", gcc_bam_dma_ahb_clk.c, "", OFF),
CLK_DUMMY("", gcc_bam_dma_inactivity_timers_clk.c, "", OFF),
- CLK_DUMMY("", gcc_blsp1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c", 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("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c",
+ 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),
@@ -345,6 +348,27 @@
CLK_DUMMY("", vpu_maple_clk.c, "", OFF),
CLK_DUMMY("", vpu_sleep_clk.c, "", OFF),
CLK_DUMMY("", vpu_vdp_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fda44000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fda44000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fda44000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd928000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd928000.qcom,iommu", oFF),
+ CLK_DUMMY("core_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9bc4000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9bc4000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdee4000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdee4000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fe054000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fe054000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fe064000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fe064000.qcom,iommu", OFF),
};
struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1f0d328..1477541 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -1789,27 +1790,73 @@
},
};
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &xo.c,
- .dbg_name = "dsipll0_byte_clk_src",
- .ops = &clk_ops_dsi_byte_pll,
- CLK_INIT(dsipll0_byte_clk_src),
-};
+struct clk_ops clk_ops_pixel_clock;
-static struct clk dsipll0_pixel_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &xo.c,
- .dbg_name = "dsipll0_pixel_clk_src",
- .ops = &clk_ops_dsi_pixel_pll,
- CLK_INIT(dsipll0_pixel_clk_src),
-};
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ return (src_rate * frac_num[i]) / frac_den[i];
+ }
+
+ return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ rc = clk_set_rate(clk->parent, src_rate);
+ if (rc)
+ return rc;
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac_den[i] == frac_num[i]) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac_num[i];
+ pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+ pixel_freq->d_val = ~frac_den[i];
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
static struct clk_freq_tbl pixel_freq_tbl[] = {
{
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+ .src_clk = &pixel_clk_src_8226.c,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
},
F_END
};
@@ -1819,7 +1866,7 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8226.c,
.dbg_name = "pclk0_clk_src",
.ops = &clk_ops_pixel,
VDD_DIG_FMAX_MAP2(LOW, 83330000, NOMINAL, 166670000),
@@ -2006,7 +2053,7 @@
static struct clk_freq_tbl byte_freq_tbl[] = {
{
- .src_clk = &dsipll0_byte_clk_src,
+ .src_clk = &byte_clk_src_8226.c,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
},
F_END
@@ -2017,7 +2064,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8226.c,
.dbg_name = "byte0_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
@@ -2764,7 +2811,7 @@
vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
- F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -3465,6 +3512,13 @@
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd404000.qcom,qcrypto"),
+ /* DSI PLL clocks */
+ CLK_LOOKUP("", dsi_vco_clk_8226.c, ""),
+ CLK_LOOKUP("", analog_postdiv_clk_8226.c, ""),
+ CLK_LOOKUP("", indirect_path_div2_clk_8226.c, ""),
+ CLK_LOOKUP("", pixel_clk_src_8226.c, ""),
+ CLK_LOOKUP("", byte_mux_8226.c, ""),
+ CLK_LOOKUP("", byte_clk_src_8226.c, ""),
};
static struct clk_lookup msm_clocks_8226_rumi[] = {
@@ -3508,6 +3562,9 @@
*/
clk_prepare_enable(&xo_a_clk.c);
+ /* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
+ clk_set_rate(&axi_clk_src.c, 200000000);
+
/* Set rates for single-rate clocks. */
clk_set_rate(&usb_hs_system_clk_src.c,
usb_hs_system_clk_src.freq_tbl[0].freq_hz);
@@ -3587,9 +3644,6 @@
*/
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
- /* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
- clk_set_rate(&axi_clk_src.c, 200000000);
-
enable_rpm_scaling();
reg_init();
@@ -3600,6 +3654,10 @@
vfe0_clk_src.c.fmax = camss_vfe_vfe0_fmax_v2;
}
+ clk_ops_pixel_clock = clk_ops_pixel;
+ clk_ops_pixel_clock.set_rate = set_rate_pixel;
+ clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
/*
* MDSS needs the ahb clock and needs to init before we register the
* lookup table.
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 5df3f3e..e34b539 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -543,7 +543,7 @@
vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
- F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -2878,6 +2878,7 @@
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9926000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
@@ -2885,6 +2886,7 @@
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, "f9926000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 9ee4476..1e91d5b 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3526,6 +3526,7 @@
/*Shared by 8064, and 8930*/
static struct clk_freq_tbl clk_tbl_gfx3d[] = {
F_GFX3D( 0, gnd, 0, 0),
+ F_GFX3D( 1800000, pxo, 1, 15),
F_GFX3D( 27000000, pxo, 0, 0),
F_GFX3D( 48000000, pll8, 1, 8),
F_GFX3D( 54857000, pll8, 1, 7),
@@ -5436,9 +5437,9 @@
CLK_LOOKUP("npl_clk", npl_tv_clk.c, ""),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "kgsl-3d0.0"),
- CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.2"),
+ CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.11"),
CLK_LOOKUP("bus_clk",
- gfx3d_axi_clk.c, "footswitch-8x60.2"),
+ gfx3d_axi_clk.c, "footswitch-8x60.11"),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, ""),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, "msm_vcap.0"),
CLK_LOOKUP("iface_clk", vcap_p_clk.c, "footswitch-8x60.10"),
@@ -5492,7 +5493,7 @@
CLK_LOOKUP("master_iface_clk", dsi2_m_p_clk.c, "mipi_dsi.2"),
CLK_LOOKUP("slave_iface_clk", dsi2_s_p_clk.c, "mipi_dsi.2"),
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "kgsl-3d0.0"),
- CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
+ CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.11"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("slave_iface_clk", hdmi_s_p_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("iface_clk", ijpeg_p_clk.c, "msm_gemini.0"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 53e35ef..3aef106 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -784,6 +785,7 @@
static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_pm_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
@@ -3011,26 +3013,9 @@
},
};
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &cxo_clk_src.c,
- .dbg_name = "dsipll0_byte_clk_src",
- .ops = &clk_ops_dsi_byte_pll,
- CLK_INIT(dsipll0_byte_clk_src),
-};
-
-static struct clk dsipll0_pixel_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &cxo_clk_src.c,
- .dbg_name = "dsipll0_pixel_clk_src",
- .ops = &clk_ops_dsi_pixel_pll,
- CLK_INIT(dsipll0_pixel_clk_src),
-};
-
static struct clk_freq_tbl byte_freq_tbl[] = {
{
- .src_clk = &dsipll0_byte_clk_src,
+ .src_clk = &byte_clk_src_8974.c,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
},
F_END
@@ -3041,7 +3026,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8974.c,
.dbg_name = "byte0_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3055,7 +3040,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8974.c,
.dbg_name = "byte1_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3235,10 +3220,73 @@
},
};
+struct clk_ops clk_ops_pixel_clock;
+
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ return (src_rate * frac_num[i]) / frac_den[i];
+ }
+
+ return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ rc = clk_set_rate(clk->parent, src_rate);
+ if (rc)
+ return rc;
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac_den[i] == frac_num[i]) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac_num[i];
+ pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+ pixel_freq->d_val = ~frac_den[i];
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
+
static struct clk_freq_tbl pixel_freq_tbl[] = {
{
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+ .src_clk = &pixel_clk_src_8974.c,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
},
F_END
};
@@ -3248,9 +3296,9 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8974.c,
.dbg_name = "pclk0_clk_src",
- .ops = &clk_ops_pixel,
+ .ops = &clk_ops_pixel_clock,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk0_clk_src.c),
},
@@ -3261,9 +3309,9 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8974.c,
.dbg_name = "pclk1_clk_src",
- .ops = &clk_ops_pixel,
+ .ops = &clk_ops_pixel_clock,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk1_clk_src.c),
},
@@ -5171,6 +5219,7 @@
CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("bus_clk", pnoc_pm_clk.c, "pm_8x60"),
CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
@@ -5252,6 +5301,14 @@
CLK_LOOKUP("krait1_m_clk", krait1_m_clk, ""),
CLK_LOOKUP("krait2_m_clk", krait2_m_clk, ""),
CLK_LOOKUP("krait3_m_clk", krait3_m_clk, ""),
+
+ /* DSI PLL clocks */
+ CLK_LOOKUP("", dsi_vco_clk_8974.c, ""),
+ CLK_LOOKUP("", analog_postdiv_clk_8974.c, ""),
+ CLK_LOOKUP("", indirect_path_div2_clk_8974.c, ""),
+ CLK_LOOKUP("", pixel_clk_src_8974.c, ""),
+ CLK_LOOKUP("", byte_mux_8974.c, ""),
+ CLK_LOOKUP("", byte_clk_src_8974.c, ""),
};
static struct pll_config_regs mmpll0_regs __initdata = {
@@ -5534,6 +5591,10 @@
qup_i2c_clks[i][0]->parent = qup_i2c_clks[i][1];
}
+ clk_ops_pixel_clock = clk_ops_pixel;
+ clk_ops_pixel_clock.set_rate = set_rate_pixel;
+ clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
/*
* MDSS needs the ahb clock and needs to init before we register the
* lookup table.
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 24af44e..fd790e2 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -698,7 +698,7 @@
enum handoff pixel_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
- u32 div_val, mval, nval, cfg_regval;
+ u32 div_val = 0, mval = 0, nval = 0, cfg_regval;
unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
@@ -712,6 +712,15 @@
clk->rate = pre_div_rate;
+ /*
+ * Pixel clocks have one frequency entry in their frequency table.
+ * Update that entry.
+ */
+ if (rcg->current_freq) {
+ rcg->current_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ rcg->current_freq->div_src_val |= div_val;
+ }
+
/* If MND is used, find the rate after the MND division */
if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
mval = readl_relaxed(M_REG(rcg));
@@ -719,6 +728,11 @@
if (!nval)
return HANDOFF_DISABLED_CLK;
nval = (~nval) + mval;
+ if (rcg->current_freq) {
+ rcg->current_freq->n_val = ~(nval - mval);
+ rcg->current_freq->m_val = mval;
+ rcg->current_freq->d_val = ~nval;
+ }
clk->rate = (pre_div_rate * mval) / nval;
}
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index f307a2f..cee5b8c 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -34,9 +34,9 @@
struct clk_freq_tbl {
unsigned long freq_hz;
struct clk *src_clk;
- const u32 m_val;
- const u32 n_val;
- const u32 d_val;
+ u32 m_val;
+ u32 n_val;
+ u32 d_val;
u32 div_src_val;
const unsigned sys_vdd;
};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
deleted file mode 100644
index edfaf90..0000000
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* 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/io.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/iopoll.h>
-#include <linux/clk.h>
-
-#include <asm/processor.h>
-#include <mach/msm_iomap.h>
-#include <mach/clk-provider.h>
-
-#include "clock-mdss-8226.h"
-
-#define REG_R(addr) readl_relaxed(addr)
-#define REG_W(data, addr) writel_relaxed(data, addr)
-
-#define GDSC_PHYS 0xFD8C2304
-#define GDSC_SIZE 0x4
-
-#define DSI_PHY_PHYS 0xFD922800
-#define DSI_PHY_SIZE 0x00000800
-
-static unsigned char *mdss_dsi_base;
-static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
-
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
- BUG_ON(ahb_clk == NULL);
-
- gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
- if (!gdsc_base)
- pr_err("%s: unable to remap gdsc base", __func__);
-
- mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
- if (!mdss_dsi_base)
- pr_err("%s: unable to remap dsi base", __func__);
-
- mdss_dsi_ahb_clk = ahb_clk;
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
-static int mdss_gdsc_enabled(void)
-{
- if (!gdsc_base)
- return 0;
-
- return !!(readl_relaxed(gdsc_base) & BIT(31));
-}
-
-static int mdss_dsi_check_pll_lock(void)
-{
- u32 status;
-
- /* poll for PLL ready status */
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & BIT(0)) == 1),
- PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pll_initialized = 0;
- } else {
- pll_initialized = 1;
- }
-
- return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- return pll_byte_clk_rate;
- } else {
- pr_err("%s: DSI PLL not configured\n", __func__);
- return -EINVAL;
- }
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- return pll_pclk_rate;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- pll_pclk_rate = rate;
- pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
- return 0;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- pr_debug("%s: rate=%ld\n", __func__, rate);
-
- if (pll_initialized)
- return 0;
-
- REG_W(0x70, mdss_dsi_base + 0x0230); /* LPFC1 CFG */
- REG_W(0x08, mdss_dsi_base + 0x022c); /* LPFR CFG */
- REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- REG_W(0x00, mdss_dsi_base + 0x0204); /* postDiv1 */
- REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- REG_W(0x03, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
- REG_W(0x0b, mdss_dsi_base + 0x023c); /* SDM CFG1 */
- REG_W(0x00, mdss_dsi_base + 0x0240); /* SDM CFG2 */
- REG_W(0x6c, mdss_dsi_base + 0x0244); /* SDM CFG3 */
- REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
- REG_W(0x31, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- REG_W(0x15, mdss_dsi_base + 0x0234); /* LPFC2 CFG */
-
- REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
- REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
- REG_W(0x60, mdss_dsi_base + 0x028c); /* CAL CFG8 */
- REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
- REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
- REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
-
- REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
- REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
- REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
- REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
- REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
- dsi_pll_rate = rate;
- pll_byte_clk_rate = rate;
-
- pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
- pll_initialized = 1;
-
- return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- ret = __mdss_dsi_pll_byte_set_rate(c, rate);
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return ret;
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
- /*
- * Add hardware recommended delays after toggling the
- * software reset bit off and back on.
- */
- REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(300);
- REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(300);
-}
-
-static void mdss_dsi_pll_enable_casem(void)
-{
- int i;
-
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- for (i = 0; (i < 3) && !mdss_dsi_check_pll_lock(); i++) {
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
-
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- }
-
- if (pll_initialized)
- pr_debug("%s: PLL Locked after %d attempts\n", __func__, i);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casef1(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_cased(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casec(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casee(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
- if (!pll_initialized) {
- if (dsi_pll_rate)
- __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
- else
- pr_err("%s: Calling clk_en before set_rate\n",
- __func__);
- }
-
- /*
- * Try all PLL power-up sequences one-by-one until
- * PLL lock is detected
- */
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casem();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_cased();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_cased();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casef1();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casec();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casee();
- if (pll_initialized)
- goto pll_locked;
-
- pr_err("%s: DSI PLL failed to Lock\n", __func__);
- return -EINVAL;
-
-pll_locked:
- pr_debug("%s: PLL Lock success\n", __func__);
-
- return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
- writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- pr_debug("%s: PLL disabled\n", __func__);
- pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
- goto out;
- if (dsipll_refcount == 1)
- __mdss_dsi_pll_disable();
- dsipll_refcount--;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (dsipll_refcount == 0) {
- ret = __mdss_dsi_pll_enable(c);
- if (ret < 0)
- goto out;
- }
- dsipll_refcount++;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
- return ret;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled()) {
- clk_prepare_enable(mdss_dsi_ahb_clk);
- if (mdss_dsi_check_pll_lock()) {
- c->rate = 59000000;
- dsi_pll_rate = 59000000;
- pll_byte_clk_rate = 59000000;
- pll_pclk_rate = 117000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled()) {
- clk_prepare_enable(mdss_dsi_ahb_clk);
- if (mdss_dsi_check_pll_lock()) {
- c->rate = 117000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-struct clk_ops clk_ops_dsi_pixel_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_pixel_set_rate,
- .round_rate = mdss_dsi_pll_pixel_round_rate,
- .handoff = mdss_dsi_pll_pixel_handoff,
-};
-
-struct clk_ops clk_ops_dsi_byte_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_byte_set_rate,
- .round_rate = mdss_dsi_pll_byte_round_rate,
- .handoff = mdss_dsi_pll_byte_handoff,
-};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 17a6801..1245287 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -21,17 +21,21 @@
#include <asm/processor.h>
#include <mach/msm_iomap.h>
#include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
#include "clock-mdss-8974.h"
-#define REG_R(addr) readl_relaxed(addr)
-#define REG_W(data, addr) writel_relaxed(data, addr)
+#define REG_R(addr) readl_relaxed(addr)
+#define REG_W(data, addr) writel_relaxed(data, addr)
+#define DSS_REG_W(base, offset, data) REG_W((data), (base) + (offset))
+#define DSS_REG_R(base, offset) REG_R((base) + (offset))
#define GDSC_PHYS 0xFD8C2304
#define GDSC_SIZE 0x4
-#define DSI_PHY_PHYS 0xFD922800
-#define DSI_PHY_SIZE 0x00000800
+#define DSI_PHY_PHYS 0xFD922A00
+#define DSI_PHY_SIZE 0x000000D4
#define HDMI_PHY_PHYS 0xFD922500
#define HDMI_PHY_SIZE 0x0000007C
@@ -100,45 +104,60 @@
#define HDMI_UNI_PLL_CAL_CFG11 (0x0098)
#define HDMI_UNI_PLL_STATUS (0x00C0)
-#define VCO_CLK 424000000
+#define DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG (0x00000000)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG (0x00000004)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG (0x00000008)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG (0x0000000C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG (0x00000010)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG (0x00000014)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_DMUX_CFG (0x00000018)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_AMUX_CFG (0x0000001C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG (0x00000020)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG (0x00000024)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG (0x00000028)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG (0x0000002C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG (0x00000030)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG (0x00000034)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0 (0x00000038)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1 (0x0000003C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2 (0x00000040)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3 (0x00000044)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4 (0x00000048)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG0 (0x0000004C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG1 (0x00000050)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG2 (0x00000054)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG3 (0x00000058)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG0 (0x0000005C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG1 (0x00000060)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2 (0x00000064)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG (0x00000068)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0 (0x0000006C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1 (0x00000070)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG2 (0x00000074)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3 (0x00000078)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4 (0x0000007C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG5 (0x00000080)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6 (0x00000084)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7 (0x00000088)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8 (0x0000008C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9 (0x00000090)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10 (0x00000094)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11 (0x00000098)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG (0x0000009C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_STATUS (0x000000C0)
+
+#define PLL_POLL_MAX_READS 10
+#define PLL_POLL_TIMEOUT_US 50
+
+static long vco_cached_rate;
static unsigned char *mdss_dsi_base;
static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
+static struct clk *mdss_ahb_clk;
static void __iomem *hdmi_phy_base;
static void __iomem *hdmi_phy_pll_base;
static unsigned hdmi_pll_on;
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
- BUG_ON(ahb_clk == NULL);
-
- gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
- if (!gdsc_base)
- pr_err("%s: unable to remap gdsc base", __func__);
-
- mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
- if (!mdss_dsi_base)
- pr_err("%s: unable to remap dsi base", __func__);
-
- mdss_dsi_ahb_clk = ahb_clk;
-
- hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
- if (!hdmi_phy_base)
- pr_err("%s: unable to ioremap hdmi phy base", __func__);
-
- hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
- if (!hdmi_phy_pll_base)
- pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
static int mdss_gdsc_enabled(void)
{
if (!gdsc_base)
@@ -147,297 +166,13 @@
return !!(readl_relaxed(gdsc_base) & BIT(31));
}
-static int mdss_dsi_check_pll_lock(void)
-{
- u32 status;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- /* poll for PLL ready status */
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & BIT(0)) == 1),
- PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pll_initialized = 0;
- } else {
- pll_initialized = 1;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized)
- return pll_byte_clk_rate;
- else {
- pr_err("%s: DSI PLL not configured\n",
- __func__);
- return -EINVAL;
- }
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized)
- return pll_pclk_rate;
- else {
- pr_err("%s: Configure Byte clk first\n",
- __func__);
- return -EINVAL;
- }
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- pll_pclk_rate = rate;
- pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
- return 0;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int pll_divcfg1, pll_divcfg2;
- int half_bitclk_rate;
-
- pr_debug("%s:\n", __func__);
- if (pll_initialized)
- return 0;
-
- half_bitclk_rate = rate * 4;
-
- pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
-
- /* Configuring the VCO to 424 Mhz */
- /* Configuring the half rate Bit clk to 212 Mhz */
-
- pll_divcfg2 = 3; /* ByteClk is 1/4 the half-bitClk rate */
-
- /* Configure the Loop filter */
- /* Loop filter resistance value */
- REG_W(0x08, mdss_dsi_base + 0x022c);
- /* Loop filter capacitance values : c1 and c2 */
- REG_W(0x70, mdss_dsi_base + 0x0230);
- REG_W(0x15, mdss_dsi_base + 0x0234);
-
- REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
- REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
- REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
-
- REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
-
- REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
- REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
- REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
- REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
-
- REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x71, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
-
- REG_W(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
- REG_W(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
- REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
- REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
- REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
- REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
- REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
- REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
- dsi_pll_rate = rate;
- pll_byte_clk_rate = rate;
-
- pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
- pll_initialized = 1;
-
- return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- ret = __mdss_dsi_pll_byte_set_rate(c, rate);
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return ret;
-}
-
-static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
-{
- REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
- udelay(100);
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
- udelay(500);
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
- REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(1);
- REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(1);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
- u32 status;
- u32 max_reads, timeout_us;
- int i;
-
- if (!pll_initialized) {
- if (dsi_pll_rate)
- __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
- else
- pr_err("%s: Calling clk_en before set_rate\n",
- __func__);
- }
-
- mdss_dsi_uniphy_pll_sw_reset();
- /* PLL power up */
- /* Add HW recommended delay between
- register writes for the update to propagate */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- for (i = 0; i < 3; i++) {
- mdss_dsi_uniphy_pll_lock_detect_setting();
- /* poll for PLL ready status */
- max_reads = 5;
- timeout_us = 100;
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & 0x01) == 1),
- max_reads, timeout_us)) {
- pr_debug("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pr_debug("%s:Trying to power UP PLL again\n",
- __func__);
- } else
- break;
-
- mdss_dsi_uniphy_pll_sw_reset();
- udelay(1000);
- /* Add HW recommended delay between
- register writes for the update to propagate */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(2000);
-
- }
-
- if ((status & 0x01) != 1) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- return -EINVAL;
- }
-
- pr_debug("%s: **** PLL Lock success\n", __func__);
-
- return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
- writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- pr_debug("%s: **** disable pll Initialize\n", __func__);
- pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
- goto out;
- if (dsipll_refcount == 1)
- __mdss_dsi_pll_disable();
- dsipll_refcount--;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (dsipll_refcount == 0) {
- ret = __mdss_dsi_pll_enable(c);
- if (ret < 0)
- goto out;
- }
- dsipll_refcount++;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
- return ret;
-}
-
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 52954560;
- dsi_pll_rate = 52954560;
- pll_byte_clk_rate = 52954560;
- pll_pclk_rate = 105000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 105000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
void hdmi_pll_disable(void)
{
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
udelay(5);
REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
hdmi_pll_on = 0;
} /* hdmi_pll_disable */
@@ -447,7 +182,7 @@
u32 status;
u32 max_reads, timeout_us;
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
/* Global Enable */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
/* Power up power gen */
@@ -473,7 +208,7 @@
pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy pll is locked\n", __func__);
@@ -487,11 +222,11 @@
pr_err("%s: hdmi phy status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy is locked\n", __func__);
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
hdmi_pll_on = 1;
@@ -507,7 +242,7 @@
set_power_dwn = 1;
}
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
pr_debug("%s: rate=%ld\n", __func__, rate);
switch (rate) {
case 0:
@@ -922,7 +657,7 @@
/* Make sure writes complete before disabling iface clock */
mb();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
if (set_power_dwn)
hdmi_pll_enable();
@@ -930,18 +665,977 @@
return 0;
} /* hdmi_pll_set_rate */
-struct clk_ops clk_ops_dsi_pixel_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_pixel_set_rate,
- .round_rate = mdss_dsi_pll_pixel_round_rate,
- .handoff = mdss_dsi_pll_pixel_handoff,
+/* Auto PLL calibaration */
+int mdss_ahb_clk_enable(int enable)
+{
+ int rc = 0;
+
+ /* todo: Ideally, we should enable/disable GDSC whenever we are
+ * attempting to enable/disable MDSS AHB clock.
+ * For now, just return error if GDSC is not enabled.
+ */
+ if (!mdss_gdsc_enabled())
+ return -EPERM;
+
+ if (enable)
+ rc = clk_prepare_enable(mdss_ahb_clk);
+ else
+ clk_disable_unprepare(mdss_ahb_clk);
+
+ return rc;
+}
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel)
+{
+ pr_debug("%s: byte mux set to %s mode\n", __func__,
+ sel ? "indirect" : "direct");
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG,
+ (sel << 1));
+ return 0;
+}
+
+int get_byte_mux_sel(struct mux_clk *clk)
+{
+ int mux_mode;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 0;
+ }
+
+ mux_mode = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG)
+ & BIT(1);
+ pr_debug("%s: byte mux mode = %s", __func__,
+ mux_mode ? "indirect" : "direct");
+
+ mdss_ahb_clk_enable(0);
+ return !!mux_mode;
+}
+
+static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+{
+ return container_of(clk, struct dsi_pll_vco_clk, c);
+}
+
+/*
+ * When the display is turned off, the display registers are wiped out.
+ * Temporarily use the prepare ops to restore the register values.
+ *
+*/
+int div_prepare(struct clk *c)
+{
+ struct div_clk *div = to_div_clk(c);
+ /* Restore the divider's value */
+ return div->ops->set_div(div, div->div);
+}
+
+int mux_prepare(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int i, rc, sel = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ for (i = 0; i < mux->num_parents; i++)
+ if (mux->parents[i].src == c->parent) {
+ sel = mux->parents[i].sel;
+ break;
+ }
+
+ if (i == mux->num_parents) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Restore the mux source select value */
+ rc = mux->ops->set_mux_sel(mux, sel);
+
+error:
+ mdss_ahb_clk_enable(0);
+ return rc;
+}
+
+static int fixed_4div_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG,
+ (div - 1));
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int fixed_4div_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static int digital_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG,
+ (div - 1));
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int digital_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static int analog_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG,
+ div - 1);
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int analog_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1;
+ mdss_ahb_clk_enable(0);
+ return div;
+}
+
+static int dsi_pll_lock_status(void)
+{
+ u32 status;
+ int pll_locked = 0;
+
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((mdss_dsi_base +
+ DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+ status,
+ ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+
+ return pll_locked;
+}
+
+static void dsi_pll_software_reset(void)
+{
+ /*
+ * Add HW recommended delays after toggling the software
+ * reset bit off and back on.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+ udelay(1000);
+}
+
+static int dsi_pll_enable_seq_m(void)
+{
+ int i = 0;
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ do {
+ pll_locked = dsi_pll_lock_status();
+ if (!pll_locked) {
+ DSS_REG_W(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+ i++;
+ }
+ } while ((i < 3) && !pll_locked);
+
+ if (pll_locked)
+ pr_debug("%s: PLL Locked at attempt #%d\n", __func__, i);
+ else
+ pr_debug("%s: PLL failed to lock after %d attempt(s)\n",
+ __func__, i);
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_d(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_f1(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_c(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_e(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_8974(void)
+{
+ int i, rc = 0;
+ u32 status, max_reads, timeout_us;
+
+ dsi_pll_software_reset();
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ for (i = 0; i < 3; i++) {
+ /* DSI Uniphy lock detect setting */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x04);
+ udelay(100);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x05);
+ udelay(500);
+ /* poll for PLL ready status */
+ max_reads = 5;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((mdss_dsi_base +
+ DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+ status,
+ ((status & 0x01) == 1),
+ max_reads, timeout_us)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pr_debug("%s:Trying to power UP PLL again\n",
+ __func__);
+ } else {
+ break;
+ }
+
+ dsi_pll_software_reset();
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf);
+ udelay(2000);
+
+ }
+
+ if ((status & 0x01) != 1) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pr_debug("%s: DSI PLL Lock success\n", __func__);
+
+error:
+ return rc;
+}
+
+static int vco_enable(struct clk *c)
+{
+ int i, rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Try all enable sequences until one succeeds */
+ for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+ rc = vco->pll_enable_seqs[i]();
+ pr_debug("%s: DSI PLL %s after sequence #%d\n", __func__,
+ rc ? "unlocked" : "locked", i + 1);
+ if (!rc)
+ break;
+ }
+ clk_disable(mdss_ahb_clk);
+
+ if (rc)
+ pr_err("%s: DSI PLL failed to lock\n", __func__);
+
+ return rc;
+}
+
+static void vco_disable(struct clk *c)
+{
+ int rc = 0;
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00);
+
+ clk_disable(mdss_ahb_clk);
+ pr_debug("%s: DSI PLL Disabled\n", __func__);
+ return;
+}
+
+static int vco_set_rate(struct clk *c, unsigned long rate)
+{
+ s64 vco_clk_rate = rate;
+ s32 rem;
+ s64 refclk_cfg, frac_n_mode, ref_doubler_en_b;
+ s64 ref_clk_to_pll, div_fbx1000, frac_n_value;
+ s64 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
+ s64 gen_vco_clk, cal_cfg10, cal_cfg11;
+ u32 res;
+ int i, rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Configure the Loop filter resistance */
+ for (i = 0; i < vco->lpfr_lut_size; i++)
+ if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate)
+ break;
+ if (i == vco->lpfr_lut_size) {
+ pr_err("%s: unable to get loop filter resistance. vco=%ld\n",
+ __func__, rate);
+ rc = -EINVAL;
+ goto error;
+ }
+ res = vco->lpfr_lut[i].r;
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG, res);
+
+ /* Loop filter capacitance values : c1 and c2 */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15);
+
+ div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem);
+ if (rem) {
+ refclk_cfg = 0x1;
+ frac_n_mode = 1;
+ ref_doubler_en_b = 0;
+ } else {
+ refclk_cfg = 0x0;
+ frac_n_mode = 0;
+ ref_doubler_en_b = 1;
+ }
+
+ pr_debug("%s:refclk_cfg = %lld\n", __func__, refclk_cfg);
+
+ ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (refclk_cfg))
+ + (ref_doubler_en_b * vco->ref_clk_rate));
+ div_fbx1000 = div_s64((vco_clk_rate * 1000), ref_clk_to_pll);
+
+ div_s64_rem(div_fbx1000, 1000, &rem);
+ frac_n_value = div_s64((rem * (1 << 16)), 1000);
+ gen_vco_clk = div_s64(div_fbx1000 * ref_clk_to_pll, 1000);
+
+ pr_debug("%s:ref_clk_to_pll = %lld\n", __func__, ref_clk_to_pll);
+ pr_debug("%s:div_fb = %lld\n", __func__, div_fbx1000);
+ pr_debug("%s:frac_n_value = %lld\n", __func__, frac_n_value);
+
+ pr_debug("%s:Generated VCO Clock: %lld\n", __func__, gen_vco_clk);
+ rem = 0;
+ if (frac_n_mode) {
+ sdm_cfg0 = (0x0 << 5);
+ sdm_cfg0 |= (0x0 & 0x3f);
+ sdm_cfg1 = (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+ sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem);
+ sdm_cfg2 = rem;
+ } else {
+ sdm_cfg0 = (0x1 << 5);
+ sdm_cfg0 |= (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+ sdm_cfg1 = (0x0 & 0x3f);
+ sdm_cfg2 = 0;
+ sdm_cfg3 = 0;
+ }
+
+ pr_debug("%s: sdm_cfg0=%lld\n", __func__, sdm_cfg0);
+ pr_debug("%s: sdm_cfg1=%lld\n", __func__, sdm_cfg1);
+ pr_debug("%s: sdm_cfg2=%lld\n", __func__, sdm_cfg2);
+ pr_debug("%s: sdm_cfg3=%lld\n", __func__, sdm_cfg3);
+
+ cal_cfg11 = div_s64_rem(gen_vco_clk, 256 * 1000000, &rem);
+ cal_cfg10 = rem / 1000000;
+ pr_debug("%s: cal_cfg10=%lld, cal_cfg11=%lld\n", __func__,
+ cal_cfg10, cal_cfg11);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+ (u32)(sdm_cfg1 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+ (u32)(sdm_cfg2 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+ (u32)(sdm_cfg3 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00);
+
+ /* Add hardware recommended delay for correct PLL configuration */
+ udelay(1000);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
+ (u32)refclk_cfg);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
+ (u32)sdm_cfg0);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x0a);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10,
+ (u32)(cal_cfg10 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11,
+ (u32)(cal_cfg11 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20);
+
+error:
+ mdss_ahb_clk_enable(0);
+ return rc;
+}
+
+/* rate is the bit clk rate */
+static long vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ return rrate;
+}
+
+static unsigned long vco_get_rate(struct clk *c)
+{
+ u32 sdm0, doubler, sdm_byp_div;
+ u64 vco_rate;
+ u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ u64 ref_clk = vco->ref_clk_rate;
+
+ /* Check to see if the ref clk doubler is enabled */
+ doubler = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG)
+ & BIT(0);
+ ref_clk += (doubler * vco->ref_clk_rate);
+
+ /* see if it is integer mode or sdm mode */
+ sdm0 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0);
+ if (sdm0 & BIT(6)) {
+ /* integer mode */
+ sdm_byp_div = (DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1;
+ vco_rate = ref_clk * sdm_byp_div;
+ } else {
+ /* sdm mode */
+ sdm_dc_off = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF;
+ pr_debug("%s: sdm_dc_off = %d\n", __func__, sdm_dc_off);
+ sdm2 = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF;
+ sdm3 = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF;
+ sdm_freq_seed = (sdm3 << 8) | sdm2;
+ pr_debug("%s: sdm_freq_seed = %d\n", __func__, sdm_freq_seed);
+
+ vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+ mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+ pr_debug("%s: vco rate = %lld", __func__, vco_rate);
+ }
+
+ pr_debug("%s: returning vco rate = %lu\n", __func__,
+ (unsigned long)vco_rate);
+ return (unsigned long)vco_rate;
+}
+
+static enum handoff vco_handoff(struct clk *c)
+{
+ int rc = 0;
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return ret;
+ }
+ if (dsi_pll_lock_status()) {
+ c->rate = vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ }
+
+ mdss_ahb_clk_enable(0);
+ return ret;
+}
+
+static int vco_prepare(struct clk *c)
+{
+ return vco_set_rate(c, vco_cached_rate);
+}
+
+static void vco_unprepare(struct clk *c)
+{
+ vco_cached_rate = c->rate;
+}
+
+/* Op structures */
+
+static struct clk_ops clk_ops_dsi_vco = {
+ .enable = vco_enable,
+ .disable = vco_disable,
+ .set_rate = vco_set_rate,
+ .round_rate = vco_round_rate,
+ .handoff = vco_handoff,
+ .prepare = vco_prepare,
+ .unprepare = vco_unprepare,
};
-struct clk_ops clk_ops_dsi_byte_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_byte_set_rate,
- .round_rate = mdss_dsi_pll_byte_round_rate,
- .handoff = mdss_dsi_pll_byte_handoff,
+static struct clk_div_ops fixed_2div_ops;
+
+static struct clk_div_ops fixed_4div_ops = {
+ .set_div = fixed_4div_set_div,
+ .get_div = fixed_4div_get_div,
};
+
+static struct clk_div_ops analog_postdiv_ops = {
+ .set_div = analog_set_div,
+ .get_div = analog_get_div,
+};
+
+static struct clk_div_ops digital_postdiv_ops = {
+ .set_div = digital_set_div,
+ .get_div = digital_get_div,
+};
+
+struct clk_mux_ops byte_mux_ops = {
+ .set_mux_sel = set_byte_mux_sel,
+ .get_mux_sel = get_byte_mux_sel,
+};
+
+struct clk_ops byte_mux_clk_ops;
+
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops analog_potsdiv_clk_ops;
+
+/* Display clocks */
+
+struct dsi_pll_vco_clk dsi_vco_clk_8226 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 350000000,
+ .max_rate = 750000000,
+ .pll_en_seq_cnt = 6,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_m,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[2] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[3] = dsi_pll_enable_seq_f1,
+ .pll_enable_seqs[4] = dsi_pll_enable_seq_c,
+ .pll_enable_seqs[5] = dsi_pll_enable_seq_e,
+ .lpfr_lut_size = 10,
+ .lpfr_lut = (struct lpfr_cfg[]){
+ {479500000, 8},
+ {480000000, 11},
+ {575500000, 8},
+ {576000000, 12},
+ {610500000, 8},
+ {659500000, 9},
+ {671500000, 10},
+ {672000000, 14},
+ {708500000, 10},
+ {750000000, 11},
+ },
+ .c = {
+ .dbg_name = "dsi_vco_clk",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8226.c),
+ },
+};
+
+struct div_clk analog_postdiv_clk_8226 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &analog_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "analog_postdiv_clk",
+ .ops = &analog_potsdiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(analog_postdiv_clk_8226.c),
+ },
+};
+
+struct div_clk indirect_path_div2_clk_8226 = {
+ .ops = &fixed_2div_ops,
+ .div = 2,
+ .c = {
+ .parent = &analog_postdiv_clk_8226.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8226.c),
+ },
+};
+
+struct div_clk pixel_clk_src_8226 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &digital_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src_8226.c),
+ },
+};
+
+struct mux_clk byte_mux_8226 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8226.c, 0},
+ {&indirect_path_div2_clk_8226.c, 1},
+ },
+ .ops = &byte_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "byte_mux",
+ .ops = &byte_mux_clk_ops,
+ CLK_INIT(byte_mux_8226.c),
+ },
+};
+
+struct div_clk byte_clk_src_8226 = {
+ .ops = &fixed_4div_ops,
+ .min_div = 4,
+ .max_div = 4,
+ .c = {
+ .parent = &byte_mux_8226.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(byte_clk_src_8226.c),
+ },
+};
+
+struct dsi_pll_vco_clk dsi_vco_clk_8974 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 350000000,
+ .max_rate = 750000000,
+ .pll_en_seq_cnt = 3,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_8974,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_8974,
+ .pll_enable_seqs[2] = dsi_pll_enable_seq_8974,
+ .lpfr_lut_size = 10,
+ .lpfr_lut = (struct lpfr_cfg[]){
+ {479500000, 8},
+ {480000000, 11},
+ {575500000, 8},
+ {576000000, 12},
+ {610500000, 8},
+ {659500000, 9},
+ {671500000, 10},
+ {672000000, 14},
+ {708500000, 10},
+ {750000000, 11},
+ },
+ .c = {
+ .dbg_name = "dsi_vco_clk",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8974.c),
+ },
+};
+
+struct div_clk analog_postdiv_clk_8974 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &analog_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "analog_postdiv_clk",
+ .ops = &analog_potsdiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(analog_postdiv_clk_8974.c),
+ },
+};
+
+struct div_clk indirect_path_div2_clk_8974 = {
+ .ops = &fixed_2div_ops,
+ .div = 2,
+ .c = {
+ .parent = &analog_postdiv_clk_8974.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8974.c),
+ },
+};
+
+struct div_clk pixel_clk_src_8974 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &digital_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src_8974.c),
+ },
+};
+
+struct mux_clk byte_mux_8974 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8974.c, 0},
+ {&indirect_path_div2_clk_8974.c, 1},
+ },
+ .ops = &byte_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "byte_mux",
+ .ops = &byte_mux_clk_ops,
+ CLK_INIT(byte_mux_8974.c),
+ },
+};
+
+struct div_clk byte_clk_src_8974 = {
+ .ops = &fixed_4div_ops,
+ .min_div = 4,
+ .max_div = 4,
+ .c = {
+ .parent = &byte_mux_8974.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(byte_clk_src_8974.c),
+ },
+};
+
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
+{
+ BUG_ON(ahb_clk == NULL);
+
+ gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
+ if (!gdsc_base)
+ pr_err("%s: unable to remap gdsc base", __func__);
+
+ mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+ if (!mdss_dsi_base)
+ pr_err("%s: unable to remap dsi base", __func__);
+
+ mdss_ahb_clk = ahb_clk;
+
+ hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
+ if (!hdmi_phy_base)
+ pr_err("%s: unable to ioremap hdmi phy base", __func__);
+
+ hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
+ if (!hdmi_phy_pll_base)
+ pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
+
+ pixel_clk_src_ops = clk_ops_slave_div;
+ pixel_clk_src_ops.prepare = div_prepare;
+
+ byte_clk_src_ops = clk_ops_div;
+ byte_clk_src_ops.prepare = div_prepare;
+
+ analog_potsdiv_clk_ops = clk_ops_div;
+ analog_potsdiv_clk_ops.prepare = div_prepare;
+
+ byte_mux_clk_ops = clk_ops_gen_mux;
+ byte_mux_clk_ops.prepare = mux_prepare;
+}
+
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index e242669..9fd3026 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -13,6 +13,10 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
+#include <linux/clk.h>
+
+#define MAX_DSI_PLL_EN_SEQS 10
+
extern struct clk_ops clk_ops_dsi_byte_pll;
extern struct clk_ops clk_ops_dsi_pixel_pll;
@@ -22,4 +26,35 @@
void hdmi_pll_disable(void);
int hdmi_pll_set_rate(unsigned long rate);
+struct lpfr_cfg {
+ unsigned long vco_rate;
+ u32 r;
+};
+
+struct dsi_pll_vco_clk {
+ unsigned long ref_clk_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
+ int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])(void);
+ u32 pll_en_seq_cnt;
+ struct lpfr_cfg *lpfr_lut;
+ u32 lpfr_lut_size;
+
+ struct clk c;
+};
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8974;
+extern struct div_clk analog_postdiv_clk_8974;
+extern struct div_clk indirect_path_div2_clk_8974;
+extern struct div_clk pixel_clk_src_8974;
+extern struct mux_clk byte_mux_8974;
+extern struct div_clk byte_clk_src_8974;
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8226;
+extern struct div_clk analog_postdiv_clk_8226;
+extern struct div_clk indirect_path_div2_clk_8226;
+extern struct div_clk pixel_clk_src_8226;
+extern struct mux_clk byte_mux_8226;
+extern struct div_clk byte_clk_src_8226;
+
#endif
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 8d99ad1..fcdcb29 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/clk.h>
#include <linux/remote_spinlock.h>
#include <mach/scm-io.h>
@@ -262,11 +263,31 @@
struct pll_clk *pll = to_pll_clk(c);
u32 mode = readl_relaxed(PLL_MODE_REG(pll));
u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL;
+ unsigned long parent_rate;
+ u32 lval, mval, nval, userval;
- if ((mode & mask) == mask)
+ if ((mode & mask) != mask)
+ return HANDOFF_DISABLED_CLK;
+
+ /* Assume bootloaders configure PLL to c->rate */
+ if (c->rate)
return HANDOFF_ENABLED_CLK;
- return HANDOFF_DISABLED_CLK;
+ parent_rate = clk_get_rate(c->parent);
+ lval = readl_relaxed(PLL_L_REG(pll));
+ mval = readl_relaxed(PLL_M_REG(pll));
+ nval = readl_relaxed(PLL_N_REG(pll));
+ userval = readl_relaxed(PLL_CONFIG_REG(pll));
+
+ c->rate = parent_rate * lval;
+
+ if (pll->masks.mn_en_mask && userval) {
+ if (!nval)
+ nval = 1;
+ c->rate += (parent_rate * mval) / nval;
+ }
+
+ return HANDOFF_ENABLED_CLK;
}
static int local_pll_clk_set_rate(struct clk *c, unsigned long rate)
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index e51a1f5..e647d1d 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -114,6 +114,11 @@
#define CPR_NUM_RING_OSC 8
#define CPR_NUM_SAVE_REGS 10
+/* RBCPR Clock Control Register */
+#define RBCPR_CLK_SEL_MASK BIT(0)
+#define RBCPR_CLK_SEL_19P2_MHZ 0
+#define RBCPR_CLK_SEL_AHB_CLK BIT(0)
+
/* CPR eFuse parameters */
#define CPR_FUSE_TARGET_QUOT_BITS 12
#define CPR_FUSE_TARGET_QUOT_BITS_MASK ((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
@@ -180,6 +185,7 @@
unsigned int cpr_irq;
void __iomem *rbcpr_base;
+ phys_addr_t rbcpr_clk_addr;
struct mutex cpr_mutex;
int ceiling_volt[CPR_CORNER_MAX];
@@ -815,10 +821,23 @@
#define cpr_regulator_resume NULL
#endif
-static void cpr_config(struct cpr_regulator *cpr_vreg)
+static int cpr_config(struct cpr_regulator *cpr_vreg)
{
int i;
- u32 val, gcnt;
+ u32 val, gcnt, reg;
+ void __iomem *rbcpr_clk;
+
+ /* Use 19.2 MHz clock for CPR. */
+ rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
+ if (!rbcpr_clk) {
+ pr_err("Unable to map rbcpr_clk\n");
+ return -EINVAL;
+ }
+ reg = readl_relaxed(rbcpr_clk);
+ reg &= ~RBCPR_CLK_SEL_MASK;
+ reg |= RBCPR_CLK_SEL_19P2_MHZ & RBCPR_CLK_SEL_MASK;
+ writel_relaxed(reg, rbcpr_clk);
+ iounmap(rbcpr_clk);
/* Disable interrupt and CPR */
cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
@@ -888,6 +907,8 @@
cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+
+ return 0;
}
static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
@@ -1199,6 +1220,13 @@
}
cpr_vreg->cpr_fuse_addr = res->start;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr_clk");
+ if (!res || !res->start) {
+ pr_err("missing rbcpr_clk address: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->rbcpr_clk_addr = res->start;
+
rc = cpr_init_cpr_efuse(cpr_vreg);
if (rc)
return rc;
@@ -1227,7 +1255,9 @@
}
/* Configure CPR HW but keep it disabled */
- cpr_config(cpr_vreg);
+ rc = cpr_config(cpr_vreg);
+ if (rc)
+ return rc;
rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
IRQF_TRIGGER_RISING, "cpr", cpr_vreg);
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index e87c7b5..7c06268 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpuidle.h>
-#include <linux/cpu_pm.h>
#include <mach/cpuidle.h>
@@ -75,8 +74,6 @@
int i;
enum msm_pm_sleep_mode pm_mode;
- cpu_pm_enter();
-
pm_mode = msm_pm_idle_enter(dev, drv, index);
for (i = 0; i < dev->state_count; i++) {
@@ -90,7 +87,6 @@
}
}
- cpu_pm_exit();
local_irq_enable();
return ret;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 14fe79d..4daccb1 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2230,11 +2230,12 @@
static struct fs_driver_data gfx3d_fs_data = {
.clks = (struct fs_clk_data[]){
- { .name = "core_clk", .reset_rate = 27000000 },
+ { .name = "core_clk", .reset_rate = 1800000 },
{ .name = "iface_clk" },
{ .name = "bus_clk" },
{ 0 }
},
+ .reset_delay_us = 10,
.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
.bus_port1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
};
@@ -2323,7 +2324,7 @@
FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data),
FS_8X60(FS_VFE, "vdd", "msm_vfe.0", &vfe_fs_data),
FS_8X60(FS_VPE, "vdd", "msm_vpe.0", &vpe_fs_data),
- FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_GFX3D_8064, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
FS_8X60(FS_VCAP, "vdd", "msm_vcap.0", &vcap_fs_data),
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index cb8ffc1..71f58a6 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -3512,7 +3512,6 @@
.num_levels = ARRAY_SIZE(grp3d_freq) + 1,
.set_grp_async = NULL,
.idle_timeout = HZ/12,
- .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp3d_bus_scale_pdata,
@@ -3579,7 +3578,6 @@
.num_levels = ARRAY_SIZE(grp2d_freq) + 1,
.set_grp_async = NULL,
.idle_timeout = HZ/5,
- .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp2d0_bus_scale_pdata,
@@ -3646,7 +3644,6 @@
.num_levels = ARRAY_SIZE(grp2d_freq) + 1,
.set_grp_async = NULL,
.idle_timeout = HZ/5,
- .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp2d1_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 907af68..446d6b6 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -942,7 +942,6 @@
.set_grp_async = set_grp_xbar_async,
.idle_timeout = HZ,
.strtstp_sleepwake = true,
- .nap_allowed = false,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
};
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 397a9d4..cdbf2ea 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1294,7 +1294,6 @@
.num_levels = 3,
.set_grp_async = set_grp3d_async,
.idle_timeout = HZ/20,
- .nap_allowed = true,
.idle_needed = true,
.clk_map = KGSL_CLK_SRC | KGSL_CLK_CORE |
KGSL_CLK_IFACE | KGSL_CLK_MEM,
@@ -1337,7 +1336,6 @@
/* HW workaround, run Z180 SYNC @ 192 MHZ */
.set_grp_async = NULL,
.idle_timeout = HZ/10,
- .nap_allowed = true,
.idle_needed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
};
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 91a7394..05858a5 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -802,7 +802,6 @@
.num_levels = 5,
.set_grp_async = NULL,
.idle_timeout = HZ/5,
- .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp3d_bus_scale_pdata,
@@ -849,7 +848,6 @@
.num_levels = 2,
.set_grp_async = NULL,
.idle_timeout = HZ/10,
- .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp2d0_bus_scale_pdata,
@@ -896,7 +894,6 @@
.num_levels = 2,
.set_grp_async = NULL,
.idle_timeout = HZ/10,
- .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp2d1_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 76ad9b8..67bbd5e 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.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
@@ -25,7 +25,10 @@
#include <mach/msm_bus.h>
#include <mach/scm-io.h>
#include <mach/clk.h>
+#include <mach/rpm.h>
+
#include "footswitch.h"
+#include "rpm_resources.h"
#ifdef CONFIG_MSM_SECURE_IO
#undef readl_relaxed
@@ -52,7 +55,7 @@
#define GFS_DELAY_CNT 31
-#define RESET_DELAY_US 1
+#define DEFAULT_RESET_DELAY_US 1
/* Clock rate to use if one has not previously been set. */
#define DEFAULT_RATE 27000000
#define MAX_CLKS 10
@@ -72,6 +75,7 @@
bool is_claimed;
struct fs_clk_data *clk_data;
struct clk *core_clk;
+ unsigned long reset_delay_us;
};
static int setup_clocks(struct footswitch *fs)
@@ -181,7 +185,7 @@
for (clock--; clock >= fs->clk_data; clock--)
clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/* Enable the power rail at the footswitch. */
regval |= ENABLE_BIT;
@@ -200,9 +204,9 @@
/* Toggle core reset again after first power-on (required for GFX3D). */
if (fs->desc.id == FS_GFX3D) {
clk_reset(fs->core_clk, CLK_RESET_ASSERT);
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
}
/* Prevent core memory from collapsing when its clock is gated. */
@@ -238,7 +242,8 @@
return rc;
/* Allow core memory to collapse when its clock is gated. */
- clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN_MEM);
+ if (fs->desc.id != FS_GFX3D_8064)
+ clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN_MEM);
/* Halt all bus ports in the power domain. */
if (fs->bus_port0) {
@@ -265,7 +270,7 @@
for (clock--; clock >= fs->clk_data; clock--)
clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/*
* Return clocks to their state before this function. For robustness
@@ -339,7 +344,7 @@
for (clock--; clock >= fs->clk_data; clock--)
clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/* Enable the power rail at the footswitch. */
regval |= ENABLE_BIT;
@@ -354,7 +359,7 @@
/* Deassert resets for all clocks in the power domain. */
for (clock = fs->clk_data; clock->clk; clock++)
clk_reset(clock->clk, CLK_RESET_DEASSERT);
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/* Re-enable core clock. */
clk_prepare_enable(fs->core_clk);
@@ -441,6 +446,120 @@
return rc;
}
+static void force_bus_clocks(bool enforce)
+{
+ static struct msm_rpm_iv_pair iv;
+ int ret;
+
+ if (enforce) {
+ iv.id = MSM_RPM_STATUS_ID_RPM_CTL;
+ ret = msm_rpm_get_status(&iv, 1);
+ if (ret)
+ pr_err("Failed to read RPM_CTL resource status\n");
+
+ iv.id = MSM_RPM_ID_RPM_CTL;
+ iv.value |= BIT(6);
+ } else {
+ iv.id = MSM_RPM_ID_RPM_CTL;
+ iv.value &= ~BIT(6);
+ }
+
+ ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+ if (ret)
+ pr_err("Force bus clocks request=%d failed\n", enforce);
+}
+
+static int gfx3d_8064_footswitch_enable(struct regulator_dev *rdev)
+{
+ struct footswitch *fs = rdev_get_drvdata(rdev);
+ struct fs_clk_data *clock;
+ uint32_t regval, rc = 0;
+
+ mutex_lock(&claim_lock);
+ fs->is_claimed = true;
+ mutex_unlock(&claim_lock);
+
+ /* Return early if already enabled. */
+ regval = readl_relaxed(fs->gfs_ctl_reg);
+ if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
+ return 0;
+
+ /* Un-halt all bus ports in the power domain. */
+ if (fs->bus_port0) {
+ rc = msm_bus_axi_portunhalt(fs->bus_port0);
+ if (rc) {
+ pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
+ goto err;
+ }
+ }
+ if (fs->bus_port1) {
+ rc = msm_bus_axi_portunhalt(fs->bus_port1);
+ if (rc) {
+ pr_err("%s port 1 unhalt failed.\n", fs->desc.name);
+ goto err_port2_halt;
+ }
+ }
+
+ /* Apply AFAB/EBI clock limits. */
+ force_bus_clocks(true);
+
+ /* Enable the power rail at the footswitch. */
+ regval |= ENABLE_BIT;
+ writel_relaxed(regval, fs->gfs_ctl_reg);
+ /* Wait for the rail to fully charge. */
+ mb();
+ udelay(1);
+
+ /* Make sure required clocks are on at the correct rates. */
+ rc = setup_clocks(fs);
+ if (rc)
+ goto err_setup_clocks;
+
+ /*
+ * (Re-)Assert resets for all clocks in the clock domain, since
+ * footswitch_enable() is first called before footswitch_disable()
+ * and resets should be asserted before power is restored.
+ */
+ for (clock = fs->clk_data; clock->clk; clock++)
+ ; /* Do nothing */
+ for (clock--; clock >= fs->clk_data; clock--)
+ clk_reset(clock->clk, CLK_RESET_ASSERT);
+ /* Wait for synchronous resets to propagate. */
+ udelay(fs->reset_delay_us);
+
+ /* Un-clamp the I/O ports. */
+ regval &= ~CLAMP_BIT;
+ writel_relaxed(regval, fs->gfs_ctl_reg);
+
+ /* Deassert resets for all clocks in the power domain. */
+ for (clock = fs->clk_data; clock->clk; clock++)
+ clk_reset(clock->clk, CLK_RESET_DEASSERT);
+
+ /* Prevent core memory from collapsing when its clock is gated. */
+ clk_set_flags(fs->core_clk, CLKFLAG_RETAIN_MEM);
+
+ /* Return clocks to their state before this function. */
+ restore_clocks(fs);
+
+ /* Remove AFAB/EBI clock limits after any transients have settled. */
+ udelay(30);
+ force_bus_clocks(false);
+
+ fs->is_enabled = true;
+ return 0;
+
+err_setup_clocks:
+ regval &= ~ENABLE_BIT;
+ writel_relaxed(regval, fs->gfs_ctl_reg);
+ force_bus_clocks(false);
+ msm_bus_axi_porthalt(fs->bus_port1);
+err_port2_halt:
+ msm_bus_axi_porthalt(fs->bus_port0);
+err:
+ return rc;
+}
+
+
static struct regulator_ops standard_fs_ops = {
.is_enabled = footswitch_is_enabled,
.enable = footswitch_enable,
@@ -453,6 +572,12 @@
.disable = gfx2d_footswitch_disable,
};
+static struct regulator_ops gfx3d_8064_fs_ops = {
+ .is_enabled = footswitch_is_enabled,
+ .enable = gfx3d_8064_footswitch_enable,
+ .disable = footswitch_disable,
+};
+
#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg) \
[(_id)] = { \
.desc = { \
@@ -467,6 +592,8 @@
static struct footswitch footswitches[] = {
FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops, GFX2D0_GFS_CTL_REG),
FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops, GFX2D1_GFS_CTL_REG),
+ FOOTSWITCH(FS_GFX3D_8064, "fs_gfx3d", &gfx3d_8064_fs_ops,
+ GFX3D_GFS_CTL_REG),
FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops, GFX3D_GFS_CTL_REG),
FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops, GEMINI_GFS_CTL_REG),
FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops, MDP_GFS_CTL_REG),
@@ -497,6 +624,8 @@
fs->clk_data = driver_data->clks;
fs->bus_port0 = driver_data->bus_port0;
fs->bus_port1 = driver_data->bus_port1;
+ fs->reset_delay_us =
+ driver_data->reset_delay_us ? : DEFAULT_RESET_DELAY_US;
for (clock = fs->clk_data; clock->name; clock++) {
clock->clk = clk_get(&pdev->dev, clock->name);
diff --git a/arch/arm/mach-msm/footswitch.h b/arch/arm/mach-msm/footswitch.h
index 2a49426..b961f42 100644
--- a/arch/arm/mach-msm/footswitch.h
+++ b/arch/arm/mach-msm/footswitch.h
@@ -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
@@ -28,7 +28,8 @@
#define FS_VFE 8
#define FS_VPE 9
#define FS_VCAP 10
-#define MAX_FS 11
+#define FS_GFX3D_8064 11
+#define MAX_FS 12
struct fs_clk_data {
const char *name;
@@ -41,6 +42,7 @@
struct fs_driver_data {
int bus_port0, bus_port1;
struct fs_clk_data *clks;
+ unsigned long reset_delay_us;
};
#define FS_GENERIC(_drv_name, _id, _name, _dev_id, _data) \
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 0e97c27..e9a4af0 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
- * 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 as
@@ -29,6 +29,9 @@
unsigned int warm_boot;
};
+
+static cpumask_t cpu_dying_mask;
+
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
msm_hotplug_devices);
@@ -70,12 +73,12 @@
int platform_cpu_kill(unsigned int cpu)
{
- int ret;
+ int ret = 0;
- ret = msm_pm_wait_cpu_shutdown(cpu);
- if (ret)
- return 0;
- return 1;
+ if (cpumask_test_and_clear_cpu(cpu, &cpu_dying_mask))
+ ret = msm_pm_wait_cpu_shutdown(cpu);
+
+ return ret ? 0 : 1;
}
/*
@@ -142,6 +145,7 @@
uncached_logk(LOGK_HOTPLUG, (void *)(cpudata | this_cpumask));
break;
case CPU_DYING:
+ cpumask_set_cpu((unsigned long)hcpu, &cpu_dying_mask);
uncached_logk(LOGK_HOTPLUG, (void *)(cpudata & ~this_cpumask));
break;
default:
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index decf9bb..68cfb2e 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -21,6 +21,8 @@
extern pgprot_t pgprot_kernel;
extern struct bus_type msm_iommu_sec_bus_type;
+extern struct iommu_access_ops iommu_access_ops_v0;
+extern struct iommu_access_ops iommu_access_ops_v1;
/* Domain attributes */
#define MSM_IOMMU_DOMAIN_PT_CACHEABLE 0x1
@@ -186,6 +188,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
@@ -193,6 +211,7 @@
*/
irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id);
enum {
PROC_APPS,
@@ -212,6 +231,8 @@
void *msm_iommu_lock_initialize(void);
void msm_iommu_mutex_lock(void);
void msm_iommu_mutex_unlock(void);
+void msm_set_iommu_access_ops(struct iommu_access_ops *ops);
+struct iommu_access_ops *msm_get_iommu_access_ops(void);
#else
static inline void *msm_iommu_lock_initialize(void)
{
@@ -219,6 +240,14 @@
}
static inline void msm_iommu_mutex_lock(void) { }
static inline void msm_iommu_mutex_unlock(void) { }
+static inline void msm_set_iommu_access_ops(struct iommu_access_ops *ops)
+{
+
+}
+static inline struct iommu_access_ops *msm_get_iommu_access_ops(void)
+{
+ return NULL;
+}
#endif
#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 554f7e0..1c20d04 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
@@ -93,6 +93,8 @@
#define SET_NSCR0(b, v) SET_GLOBAL_REG(NSCR0, (b), (v))
#define SET_NSCR2(b, v) SET_GLOBAL_REG(NSCR2, (b), (v))
#define SET_NSACR(b, v) SET_GLOBAL_REG(NSACR, (b), (v))
+#define SET_NSGFAR(b, v) SET_GLOBAL_REG(NSGFAR, (b), (v))
+#define SET_NSGFSRRESTORE(b, v) SET_GLOBAL_REG(NSGFSRRESTORE, (b), (v))
#define SET_PMCR(b, v) SET_GLOBAL_REG(PMCR, (b), (v))
#define SET_SMR_N(b, N, v) SET_GLOBAL_REG_N(SMR, N, (b), (v))
#define SET_S2CR_N(b, N, v) SET_GLOBAL_REG_N(S2CR, N, (b), (v))
@@ -215,26 +217,34 @@
#define GET_ATSR(b, c) GET_CTX_REG(CB_ATSR, (b), (c))
/* Global Register field setters / getters */
-/* Configuration Register: CR0 */
+/* Configuration Register: CR0/NSCR0 */
#define SET_CR0_NSCFG(b, v) SET_GLOBAL_FIELD(b, CR0, NSCFG, v)
#define SET_CR0_WACFG(b, v) SET_GLOBAL_FIELD(b, CR0, WACFG, v)
#define SET_CR0_RACFG(b, v) SET_GLOBAL_FIELD(b, CR0, RACFG, v)
#define SET_CR0_SHCFG(b, v) SET_GLOBAL_FIELD(b, CR0, SHCFG, v)
#define SET_CR0_SMCFCFG(b, v) SET_GLOBAL_FIELD(b, CR0, SMCFCFG, v)
+#define SET_NSCR0_SMCFCFG(b, v) SET_GLOBAL_FIELD(b, NSCR0, SMCFCFG, v)
#define SET_CR0_MTCFG(b, v) SET_GLOBAL_FIELD(b, CR0, MTCFG, v)
#define SET_CR0_BSU(b, v) SET_GLOBAL_FIELD(b, CR0, BSU, v)
#define SET_CR0_FB(b, v) SET_GLOBAL_FIELD(b, CR0, FB, v)
#define SET_CR0_PTM(b, v) SET_GLOBAL_FIELD(b, CR0, PTM, v)
#define SET_CR0_VMIDPNE(b, v) SET_GLOBAL_FIELD(b, CR0, VMIDPNE, v)
#define SET_CR0_USFCFG(b, v) SET_GLOBAL_FIELD(b, CR0, USFCFG, v)
+#define SET_NSCR0_USFCFG(b, v) SET_GLOBAL_FIELD(b, NSCR0, USFCFG, v)
#define SET_CR0_GSE(b, v) SET_GLOBAL_FIELD(b, CR0, GSE, v)
#define SET_CR0_STALLD(b, v) SET_GLOBAL_FIELD(b, CR0, STALLD, v)
+#define SET_NSCR0_STALLD(b, v) SET_GLOBAL_FIELD(b, NSCR0, STALLD, v)
#define SET_CR0_TRANSIENTCFG(b, v) SET_GLOBAL_FIELD(b, CR0, TRANSIENTCFG, v)
#define SET_CR0_GCFGFIE(b, v) SET_GLOBAL_FIELD(b, CR0, GCFGFIE, v)
+#define SET_NSCR0_GCFGFIE(b, v) SET_GLOBAL_FIELD(b, NSCR0, GCFGFIE, v)
#define SET_CR0_GCFGFRE(b, v) SET_GLOBAL_FIELD(b, CR0, GCFGFRE, v)
+#define SET_NSCR0_GCFGFRE(b, v) SET_GLOBAL_FIELD(b, NSCR0, GCFGFRE, v)
#define SET_CR0_GFIE(b, v) SET_GLOBAL_FIELD(b, CR0, GFIE, v)
+#define SET_NSCR0_GFIE(b, v) SET_GLOBAL_FIELD(b, NSCR0, GFIE, v)
#define SET_CR0_GFRE(b, v) SET_GLOBAL_FIELD(b, CR0, GFRE, v)
+#define SET_NSCR0_GFRE(b, v) SET_GLOBAL_FIELD(b, NSCR0, GFRE, v)
#define SET_CR0_CLIENTPD(b, v) SET_GLOBAL_FIELD(b, CR0, CLIENTPD, v)
+#define SET_NSCR0_CLIENTPD(b, v) SET_GLOBAL_FIELD(b, NSCR0, CLIENTPD, v)
#define GET_CR0_NSCFG(b) GET_GLOBAL_FIELD(b, CR0, NSCFG)
#define GET_CR0_WACFG(b) GET_GLOBAL_FIELD(b, CR0, WACFG)
@@ -949,6 +959,8 @@
#define NSCR0 (0x0400)
#define NSCR2 (0x0408)
#define NSACR (0x0410)
+#define NSGFAR (0x0440)
+#define NSGFSRRESTORE (0x044C)
#define SMR (0x0800)
#define S2CR (0x0C00)
@@ -1400,6 +1412,7 @@
#define CR0_RACFG_MASK 0x03
#define CR0_SHCFG_MASK 0x03
#define CR0_SMCFCFG_MASK 0x01
+#define NSCR0_SMCFCFG_MASK 0x01
#define CR0_MTCFG_MASK 0x01
#define CR0_MEMATTR_MASK 0x0F
#define CR0_BSU_MASK 0x03
@@ -1407,14 +1420,21 @@
#define CR0_PTM_MASK 0x01
#define CR0_VMIDPNE_MASK 0x01
#define CR0_USFCFG_MASK 0x01
+#define NSCR0_USFCFG_MASK 0x01
#define CR0_GSE_MASK 0x01
#define CR0_STALLD_MASK 0x01
+#define NSCR0_STALLD_MASK 0x01
#define CR0_TRANSIENTCFG_MASK 0x03
#define CR0_GCFGFIE_MASK 0x01
+#define NSCR0_GCFGFIE_MASK 0x01
#define CR0_GCFGFRE_MASK 0x01
+#define NSCR0_GCFGFRE_MASK 0x01
#define CR0_GFIE_MASK 0x01
+#define NSCR0_GFIE_MASK 0x01
#define CR0_GFRE_MASK 0x01
+#define NSCR0_GFRE_MASK 0x01
#define CR0_CLIENTPD_MASK 0x01
+#define NSCR0_CLIENTPD_MASK 0x01
/* Configuration Register 2 */
#define CR2_BPVMID_MASK 0xFF
@@ -1764,6 +1784,7 @@
#define CR0_RACFG_SHIFT 24
#define CR0_SHCFG_SHIFT 22
#define CR0_SMCFCFG_SHIFT 21
+#define NSCR0_SMCFCFG_SHIFT 21
#define CR0_MTCFG_SHIFT 20
#define CR0_MEMATTR_SHIFT 16
#define CR0_BSU_SHIFT 14
@@ -1771,14 +1792,21 @@
#define CR0_PTM_SHIFT 12
#define CR0_VMIDPNE_SHIFT 11
#define CR0_USFCFG_SHIFT 10
+#define NSCR0_USFCFG_SHIFT 10
#define CR0_GSE_SHIFT 9
#define CR0_STALLD_SHIFT 8
+#define NSCR0_STALLD_SHIFT 8
#define CR0_TRANSIENTCFG_SHIFT 6
#define CR0_GCFGFIE_SHIFT 5
+#define NSCR0_GCFGFIE_SHIFT 5
#define CR0_GCFGFRE_SHIFT 4
+#define NSCR0_GCFGFRE_SHIFT 4
#define CR0_GFIE_SHIFT 2
+#define NSCR0_GFIE_SHIFT 2
#define CR0_GFRE_SHIFT 1
+#define NSCR0_GFRE_SHIFT 1
#define CR0_CLIENTPD_SHIFT 0
+#define NSCR0_CLIENTPD_SHIFT 0
/* Configuration Register: CR2 */
#define CR2_BPVMID_SHIFT 0
diff --git a/arch/arm/mach-msm/include/mach/iommu_perfmon.h b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
index dc4671c..45683f4 100644
--- a/arch/arm/mach-msm/include/mach/iommu_perfmon.h
+++ b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
@@ -144,8 +144,6 @@
unsigned int (*read_counter)(struct iommu_pmon_counter *);
};
-extern struct iommu_access_ops iommu_access_ops_v0;
-extern struct iommu_access_ops iommu_access_ops_v1;
#define MSM_IOMMU_PMU_NO_EVENT_CLASS -1
#ifdef CONFIG_MSM_IOMMU_PMON
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index db5e126..697de5e 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -186,6 +186,16 @@
};
/**
+ * struct ipa_ep_cfg_holb - head of line blocking configuration in IPA end-point
+ * @en: enable(1 => ok to drop pkt)/disable(0 => never drop pkt)
+ * @tmr_val: duration in units of 128 IPA clk clock cyles [0,511], 1 clk=1.28us
+ */
+struct ipa_ep_cfg_holb {
+ u16 en;
+ u16 tmr_val;
+};
+
+/**
* struct ipa_ep_cfg - configuration of IPA end-point
* @nat: NAT parmeters
* @hdr: Header parameters
@@ -485,6 +495,11 @@
int ipa_cfg_ep_route(u32 clnt_hdl, const struct ipa_ep_cfg_route *ipa_ep_cfg);
+int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg);
+
+int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
+ const struct ipa_ep_cfg_holb *ipa_ep_cfg);
+
/*
* Header removal / addition
*/
@@ -754,6 +769,12 @@
return -EPERM;
}
+static inline int ipa_cfg_ep_holb(u32 clnt_hdl,
+ const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+ return -EPERM;
+}
+
/*
* Header removal / addition
*/
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 2216183..2d7e8df 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -81,7 +81,6 @@
int (*set_grp_async)(void);
unsigned int idle_timeout;
bool strtstp_sleepwake;
- unsigned int nap_allowed;
unsigned int clk_map;
unsigned int idle_needed;
unsigned int step_mul;
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 46069d2..c6c03e4 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -12,6 +12,7 @@
#ifndef _ARCH_ARM_MACH_MSM_MDM2_H
#define _ARCH_ARM_MACH_MSM_MDM2_H
+#include "sysmon.h"
struct mdm_vddmin_resource {
int rpm_id;
@@ -35,6 +36,9 @@
int image_upgrade_supported;
struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
int send_shdn;
+ int cascading_ssr;
+ int sysmon_subsys_id_valid;
+ enum subsys_id sysmon_subsys_id;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
index b675c00..0a91719 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -183,6 +183,14 @@
int add_deserialization_func(void *ctxt, int type,
void (*dfunc)(struct encode_context *,
struct decode_context *));
+
+/*
+ * ipc_log_context_destroy: Destroy debug log context
+ *
+ * @ctxt: debug log context created by calling ipc_log_context_create API.
+ */
+int ipc_log_context_destroy(void *ctxt);
+
#else
static inline void *ipc_log_context_create(int max_num_pages,
@@ -232,6 +240,9 @@
struct decode_context *))
{ return 0; }
+static inline int ipc_log_context_destroy(void *ctxt)
+{ return 0; }
+
#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 5dc1095..a87380c 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -47,7 +47,7 @@
struct comm_mode_info mode_info;
struct list_head port_rx_q;
- struct mutex port_rx_q_lock;
+ struct mutex port_rx_q_lock_lhb3;
char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
struct wake_lock port_rx_wake_lock;
wait_queue_head_t port_rx_wait_q;
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 733f5a9..f97d5e4 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -39,12 +39,16 @@
};
#endif
+/*
+ * Ordered by when processors adopted the SMSM protocol. May not be 1-to-1
+ * with SMEM PIDs, despite initial expectations.
+ */
enum {
SMSM_APPS = SMEM_APPS,
SMSM_MODEM = SMEM_MODEM,
SMSM_Q6 = SMEM_Q6,
- SMSM_DSPS = SMEM_DSPS,
- SMSM_WCNSS = SMEM_WCNSS,
+ SMSM_WCNSS,
+ SMSM_DSPS,
};
extern uint32_t SMSM_NUM_HOSTS;
diff --git a/arch/arm/mach-msm/include/mach/qcrypto.h b/arch/arm/mach-msm/include/mach/qcrypto.h
new file mode 100644
index 0000000..bb8048f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qcrypto.h
@@ -0,0 +1,36 @@
+/* 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.
+ */
+
+#ifndef _DRIVERS_CRYPTO_MSM_QCRYPTO_H_
+#define _DRIVERS_CRYPTO_MSM_QCRYPTO_H_
+
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+
+#define QCRYPTO_CTX_KEY_MASK 0x000000ff
+#define QCRYPTO_CTX_USE_HW_KEY 0x00000001
+#define QCRYPTO_CTX_USE_PIPE_KEY 0x00000002
+
+#define QCRYPTO_CTX_XTS_MASK 0x0000ff00
+#define QCRYPTO_CTX_XTS_DU_SIZE_512B 0x00000100
+#define QCRYPTO_CTX_XTS_DU_SIZE_1KB 0x00000200
+
+int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags);
+int qcrypto_ahash_set_flag(struct ahash_request *req, unsigned int flags);
+int qcrypto_aead_set_flag(struct aead_request *req, unsigned int flags);
+
+int qcrypto_cipher_clear_flag(struct ablkcipher_request *req,
+ unsigned int flags);
+int qcrypto_ahash_clear_flag(struct ahash_request *req, unsigned int flags);
+int qcrypto_aead_clear_flag(struct aead_request *req, unsigned int flags);
+
+#endif /* _DRIVERS_CRYPTO_MSM_QCRYPTO_H */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 99bff66..d52686c 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -38,6 +38,10 @@
#define of_board_is_liquid() of_machine_is_compatible("qcom,liquid")
#define of_board_is_dragonboard() \
of_machine_is_compatible("qcom,dragonboard")
+#define of_board_is_cdp() of_machine_is_compatible("qcom,cdp")
+#define of_board_is_mtp() of_machine_is_compatible("qcom,mtp")
+#define of_board_is_qrd() of_machine_is_compatible("qcom,qrd")
+#define of_board_is_xpm() of_machine_is_compatible("qcom,xpm")
#define machine_is_msm8974() of_machine_is_compatible("qcom,msm8974")
#define machine_is_msm9625() of_machine_is_compatible("qcom,msm9625")
@@ -63,6 +67,10 @@
#define of_board_is_fluid() 0
#define of_board_is_liquid() 0
#define of_board_is_dragonboard() 0
+#define of_board_is_cdp() 0
+#define of_board_is_mtp() 0
+#define of_board_is_qrd() 0
+#define of_board_is_xpm() 0
#define machine_is_msm8974() 0
#define machine_is_msm9625() 0
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 35b1f76..962429e 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -75,6 +75,8 @@
extern void subsys_unregister(struct subsys_device *dev);
extern void subsys_default_online(struct subsys_device *dev);
+extern void subsys_set_crash_status(struct subsys_device *dev, bool crashed);
+extern bool subsys_get_crash_status(struct subsys_device *dev);
#else
@@ -114,6 +116,12 @@
static inline void subsys_unregister(struct subsys_device *dev) { }
static inline void subsys_default_online(struct subsys_device *dev) { }
+static inline
+void subsys_set_crash_status(struct subsys_device *dev, bool crashed) { }
+static inline bool subsys_get_crash_status(struct subsys_device *dev)
+{
+ return false;
+}
#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index bc76f56..a3e993d 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -298,7 +298,7 @@
* Resets the USB BAM that has A2 pipes
*
*/
-int usb_bam_a2_reset(void);
+int usb_bam_a2_reset(bool to_reconnect);
/**
* Indicates if the client of the USB BAM is ready to start
@@ -308,6 +308,14 @@
*
*/
int usb_bam_client_ready(bool ready);
+
+/**
+* Returns upon reset completion if reset is in progress
+* immediately otherwise.
+*
+*/
+void usb_bam_reset_complete(void);
+
/**
* Returns qdss index from the connections array.
*
@@ -403,7 +411,7 @@
return -ENODEV;
}
-static inline int usb_bam_a2_reset(void)
+static inline int usb_bam_a2_reset(bool to_reconnect)
{
return -ENODEV;
}
@@ -413,6 +421,11 @@
return -ENODEV;
}
+static inline void usb_bam_reset_complete(void)
+{
+ return;
+}
+
static inline int usb_bam_get_qdss_idx(u8 num)
{
return -ENODEV;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 7fb2c88..f736b30 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -562,6 +562,7 @@
{
msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MPQ8092 */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 12f5a8e..20a5249 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -189,6 +189,7 @@
{
unsigned long iova;
int ret;
+ struct iommu_domain *domain;
if (size & (align - 1))
return -EINVAL;
@@ -204,8 +205,14 @@
if (ret)
return -ENOMEM;
- ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
- phys, size, cached);
+ domain = msm_get_iommu_domain(domain_no);
+ if (!domain) {
+ pr_err("%s: Could not find domain %u. Unable to map\n",
+ __func__, domain_no);
+ msm_free_iova_address(iova, domain_no, partition_no, size);
+ return -EINVAL;
+ }
+ ret = msm_iommu_map_iova_phys(domain, iova, phys, size, cached);
if (ret)
msm_free_iova_address(iova, domain_no, partition_no, size);
@@ -221,10 +228,18 @@
unsigned int partition_no,
unsigned long size)
{
+ struct iommu_domain *domain;
+
if (!msm_use_iommu())
return;
- iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
+ domain = msm_get_iommu_domain(domain_no);
+ if (domain) {
+ iommu_unmap_range(domain, iova, size);
+ } else {
+ pr_err("%s: Could not find domain %u. Unable to unmap\n",
+ __func__, domain_no);
+ }
msm_free_iova_address(iova, domain_no, partition_no, size);
}
EXPORT_SYMBOL(msm_iommu_unmap_contig_buffer);
@@ -232,10 +247,10 @@
static struct msm_iova_data *find_domain(int domain_num)
{
struct rb_root *root = &domain_root;
- struct rb_node *p = root->rb_node;
+ struct rb_node *p;
mutex_lock(&domain_mutex);
-
+ p = root->rb_node;
while (p) {
struct msm_iova_data *node;
diff --git a/arch/arm/mach-msm/ipc_logging.c b/arch/arm/mach-msm/ipc_logging.c
index 280f237..43214cc 100644
--- a/arch/arm/mach-msm/ipc_logging.c
+++ b/arch/arm/mach-msm/ipc_logging.c
@@ -544,6 +544,35 @@
}
EXPORT_SYMBOL(ipc_log_context_create);
+/*
+ * Destroy debug log context
+ *
+ * @ctxt: debug log context created by calling ipc_log_context_create API.
+ */
+int ipc_log_context_destroy(void *ctxt)
+{
+ struct ipc_log_context *ilctxt = (struct ipc_log_context *)ctxt;
+ struct ipc_log_page *pg = NULL;
+ unsigned long flags;
+
+ if (!ilctxt)
+ return 0;
+
+ while (!list_empty(&ilctxt->page_list)) {
+ pg = get_first_page(ctxt);
+ list_del(&pg->hdr.list);
+ kfree(pg);
+ }
+
+ write_lock_irqsave(&ipc_log_context_list_lock, flags);
+ list_del(&ilctxt->list);
+ write_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+
+ kfree(ilctxt);
+ return 0;
+}
+EXPORT_SYMBOL(ipc_log_context_destroy);
+
static int __init ipc_logging_init(void)
{
check_and_create_debugfs();
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 573b9a3..841ccf3 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
+#include <linux/rwsem.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -99,11 +100,11 @@
#define IPC_ROUTER_LOG_EVENT_RX 0x12
static LIST_HEAD(control_ports);
-static DEFINE_MUTEX(control_ports_lock);
+static DECLARE_RWSEM(control_ports_lock_lha5);
#define LP_HASH_SIZE 32
static struct list_head local_ports[LP_HASH_SIZE];
-static DEFINE_MUTEX(local_ports_lock);
+static DECLARE_RWSEM(local_ports_lock_lha2);
/*
* Server info is organized as a hash table. The server's service ID is
@@ -114,7 +115,7 @@
*/
#define SRV_HASH_SIZE 32
static struct list_head server_list[SRV_HASH_SIZE];
-static DEFINE_MUTEX(server_list_lock);
+static DECLARE_RWSEM(server_list_lock_lha2);
struct msm_ipc_server {
struct list_head list;
@@ -143,11 +144,11 @@
struct list_head list;
uint32_t node_id;
uint32_t port_id;
- uint32_t restart_state;
uint32_t tx_quota_cnt;
- struct mutex quota_lock;
+ struct mutex quota_lock_lhb2;
struct list_head resume_tx_port_list;
void *sec_rule;
+ struct msm_ipc_server *server;
};
struct msm_ipc_router_xprt_info {
@@ -157,8 +158,8 @@
uint32_t initialized;
struct list_head pkt_list;
struct wake_lock wakelock;
- struct mutex rx_lock;
- struct mutex tx_lock;
+ struct mutex rx_lock_lhb2;
+ struct mutex tx_lock_lhb2;
uint32_t need_len;
uint32_t abort_data_read;
struct work_struct read_data;
@@ -172,36 +173,25 @@
uint32_t neighbor_node_id;
struct list_head remote_port_list[RP_HASH_SIZE];
struct msm_ipc_router_xprt_info *xprt_info;
- struct mutex lock;
+ struct rw_semaphore lock_lha4;
unsigned long num_tx_bytes;
unsigned long num_rx_bytes;
};
static struct list_head routing_table[RT_HASH_SIZE];
-static DEFINE_MUTEX(routing_table_lock);
+static DECLARE_RWSEM(routing_table_lock_lha3);
static int routing_table_inited;
static void do_read_data(struct work_struct *work);
-#define RR_STATE_IDLE 0
-#define RR_STATE_HEADER 1
-#define RR_STATE_BODY 2
-#define RR_STATE_ERROR 3
-
-#define RESTART_NORMAL 0
-#define RESTART_PEND 1
-
-/* State for remote ep following restart */
-#define RESTART_QUOTA_ABORT 1
-
static LIST_HEAD(xprt_info_list);
-static DEFINE_MUTEX(xprt_info_list_lock);
+static DECLARE_RWSEM(xprt_info_list_lock_lha5);
static DECLARE_COMPLETION(msm_ipc_local_router_up);
#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
static uint32_t next_port_id;
-static DEFINE_MUTEX(next_port_id_lock);
+static DEFINE_MUTEX(next_port_id_lock_lha1);
static atomic_t pending_close_count = ATOMIC_INIT(0);
static wait_queue_head_t subsystem_restart_wait;
static struct workqueue_struct *msm_ipc_router_workqueue;
@@ -235,13 +225,13 @@
for (i = 0; i < RP_HASH_SIZE; i++)
INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
- mutex_init(&rt_entry->lock);
+ init_rwsem(&rt_entry->lock_lha4);
rt_entry->node_id = node_id;
rt_entry->xprt_info = NULL;
return rt_entry;
}
-/*Please take routing_table_lock before calling this function*/
+/* Must be called with routing_table_lock_lha3 locked. */
static int add_routing_table_entry(
struct msm_ipc_routing_table_entry *rt_entry)
{
@@ -255,7 +245,7 @@
return 0;
}
-/*Please take routing_table_lock before calling this function*/
+/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_routing_table_entry *lookup_routing_table(
uint32_t node_id)
{
@@ -276,16 +266,16 @@
if (!xprt_info)
return NULL;
- mutex_lock(&xprt_info->rx_lock);
+ mutex_lock(&xprt_info->rx_lock_lhb2);
if (xprt_info->abort_data_read) {
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
pr_err("%s detected SSR & exiting now\n",
xprt_info->xprt->name);
return NULL;
}
if (list_empty(&xprt_info->pkt_list)) {
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
return NULL;
}
@@ -294,7 +284,7 @@
list_del(&temp_pkt->list);
if (list_empty(&xprt_info->pkt_list))
wake_unlock(&xprt_info->wakelock);
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
return temp_pkt;
}
@@ -476,6 +466,7 @@
struct rr_packet *pkt, int clone)
{
struct rr_packet *temp_pkt = pkt;
+ void (*notify)(unsigned event, void *priv);
if (unlikely(!port_ptr || !pkt))
return -EINVAL;
@@ -490,13 +481,14 @@
}
}
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
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);
+ notify = port_ptr->notify;
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+ if (notify)
+ notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
return 0;
}
@@ -507,10 +499,10 @@
if (!pkt)
return -EINVAL;
- mutex_lock(&control_ports_lock);
+ down_read(&control_ports_lock_lha5);
list_for_each_entry(port_ptr, &control_ports, list)
post_pkt_to_port(port_ptr, pkt, 1);
- mutex_unlock(&control_ports_lock);
+ up_read(&control_ports_lock_lha5);
return 0;
}
@@ -519,9 +511,9 @@
uint32_t port_id = 0, prev_port_id, key;
struct msm_ipc_port *port_ptr;
- mutex_lock(&next_port_id_lock);
+ mutex_lock(&next_port_id_lock_lha1);
prev_port_id = next_port_id;
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
do {
next_port_id++;
if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
@@ -544,8 +536,8 @@
}
port_id = 0;
} while (next_port_id != prev_port_id);
- mutex_unlock(&local_ports_lock);
- mutex_unlock(&next_port_id_lock);
+ up_read(&local_ports_lock_lha2);
+ mutex_unlock(&next_port_id_lock_lha1);
return port_id;
}
@@ -558,9 +550,9 @@
return;
key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_add_tail(&port_ptr->list, &local_ports[key]);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
}
struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
@@ -583,7 +575,7 @@
spin_lock_init(&port_ptr->port_lock);
INIT_LIST_HEAD(&port_ptr->port_rx_q);
- mutex_init(&port_ptr->port_rx_q_lock);
+ mutex_init(&port_ptr->port_rx_q_lock_lhb3);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
"ipc%08x_%s",
@@ -600,9 +592,7 @@
return port_ptr;
}
-/*
- * Should be called with local_ports_lock locked
- */
+/* Must be called with local_ports_lock_lha2 locked. */
static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
{
int key = (port_id & (LP_HASH_SIZE - 1));
@@ -616,6 +606,7 @@
return NULL;
}
+/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
uint32_t node_id,
uint32_t port_id)
@@ -624,30 +615,25 @@
struct msm_ipc_routing_table_entry *rt_entry;
int key = (port_id & (RP_HASH_SIZE - 1));
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Node is not up\n", __func__);
return NULL;
}
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
list_for_each_entry(rport_ptr,
&rt_entry->remote_port_list[key], list) {
if (rport_ptr->port_id == port_id) {
- if (rport_ptr->restart_state != RESTART_NORMAL)
- rport_ptr = NULL;
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ up_read(&rt_entry->lock_lha4);
return rport_ptr;
}
}
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ up_read(&rt_entry->lock_lha4);
return NULL;
}
+/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
uint32_t node_id,
uint32_t port_id)
@@ -656,34 +642,29 @@
struct msm_ipc_routing_table_entry *rt_entry;
int key = (port_id & (RP_HASH_SIZE - 1));
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Node is not up\n", __func__);
return NULL;
}
- mutex_lock(&rt_entry->lock);
rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
GFP_KERNEL);
if (!rport_ptr) {
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
pr_err("%s: Remote port alloc failed\n", __func__);
return NULL;
}
rport_ptr->port_id = port_id;
rport_ptr->node_id = node_id;
- rport_ptr->restart_state = RESTART_NORMAL;
rport_ptr->sec_rule = NULL;
+ rport_ptr->server = NULL;
rport_ptr->tx_quota_cnt = 0;
- mutex_init(&rport_ptr->quota_lock);
+ mutex_init(&rport_ptr->quota_lock_lhb2);
INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
+ down_write(&rt_entry->lock_lha4);
list_add_tail(&rport_ptr->list,
&rt_entry->remote_port_list[key]);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ up_write(&rt_entry->lock_lha4);
return rport_ptr;
}
@@ -694,7 +675,7 @@
* This function deletes all the resume_tx ports associated with a remote port
* and frees the memory allocated to each resume_tx port.
*
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
*/
static void msm_ipc_router_free_resume_tx_port(
struct msm_ipc_router_remote_port *rport_ptr)
@@ -719,7 +700,7 @@
* remote port's resume_tx list. This function is used to ensure that
* the same port is not added to the remote_port's resume_tx list repeatedly.
*
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
*/
static int msm_ipc_router_lookup_resume_tx_port(
struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
@@ -744,7 +725,7 @@
* function sequentially deletes each entry in the resume_tx_port_list of the
* remote port.
*
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
*/
static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
struct rr_packet *pkt)
@@ -754,17 +735,16 @@
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)
post_pkt_to_port(local_port, pkt, 1);
- mutex_unlock(&local_ports_lock);
list_del(&rtx_port->list);
kfree(rtx_port);
}
}
+/* Must be called with routing_table_lock_lha3 locked. */
static void msm_ipc_router_destroy_remote_port(
struct msm_ipc_router_remote_port *rport_ptr)
{
@@ -775,21 +755,18 @@
return;
node_id = rport_ptr->node_id;
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Node %d is not up\n", __func__, node_id);
return;
}
- mutex_lock(&rport_ptr->quota_lock);
- msm_ipc_router_free_resume_tx_port(rport_ptr);
- mutex_unlock(&rport_ptr->quota_lock);
- mutex_lock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
list_del(&rport_ptr->list);
+ up_write(&rt_entry->lock_lha4);
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
+ msm_ipc_router_free_resume_tx_port(rport_ptr);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
kfree(rport_ptr);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
return;
}
@@ -802,7 +779,7 @@
*
* @return: If found Pointer to server structure, else NULL.
*
- * Note1: Lock the server_list_lock before accessing this function.
+ * Note1: Lock the server_list_lock_lha2 before accessing this function.
* Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
* to <service:instance>. Used only when a client wants to send a
* message to any QMI server.
@@ -850,7 +827,7 @@
* This function adds the server info to the hash table. If the same
* server(i.e. <service_id:instance_id>) is hosted in different nodes,
* they are maintained as list of "server_port" under "server" structure.
- * Note: Lock the server_list_lock before accessing this function.
+ * Note: Lock the server_list_lock_lha2 before accessing this function.
*/
static struct msm_ipc_server *msm_ipc_router_create_server(
uint32_t service,
@@ -916,7 +893,7 @@
* from the server structure. If the server_port list under server structure
* is empty after removal, then remove the server structure from the server
* hash table.
- * Note: Lock the server_list_lock before accessing this function.
+ * Note: Lock the server_list_lock_lha2 before accessing this function.
*/
static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
uint32_t node_id, uint32_t port_id)
@@ -1011,9 +988,9 @@
pkt->pkt_fragment_q = pkt_fragment_q;
pkt->length = pkt_size;
- mutex_lock(&xprt_info->tx_lock);
+ mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
- mutex_unlock(&xprt_info->tx_lock);
+ mutex_unlock(&xprt_info->tx_lock_lhb2);
release_pkt(pkt);
return ret;
@@ -1148,11 +1125,11 @@
{
struct msm_ipc_router_xprt_info *xprt_info;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(xprt_info, &xprt_info_list, list) {
msm_ipc_router_send_control_msg(xprt_info, ctl);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return 0;
}
@@ -1165,12 +1142,12 @@
if (!xprt_info || !ctl)
return -EINVAL;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return 0;
}
@@ -1183,15 +1160,15 @@
if (!xprt_info || !pkt)
return -EINVAL;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
- mutex_lock(&fwd_xprt_info->tx_lock);
+ mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
fwd_xprt_info->xprt->write(pkt, pkt->length,
fwd_xprt_info->xprt);
- mutex_unlock(&fwd_xprt_info->tx_lock);
+ mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return 0;
}
@@ -1203,6 +1180,7 @@
struct rr_header *hdr;
struct msm_ipc_router_xprt_info *fwd_xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
+ int ret = 0;
if (!xprt_info || !pkt)
return -EINVAL;
@@ -1213,38 +1191,34 @@
hdr = (struct rr_header *)head_pkt->data;
dst_node_id = hdr->dst_node_id;
- mutex_lock(&routing_table_lock);
+ down_read(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(dst_node_id);
if (!(rt_entry) || !(rt_entry->xprt_info)) {
- mutex_unlock(&routing_table_lock);
+ up_read(&routing_table_lock_lha3);
pr_err("%s: Routing table not initialized\n", __func__);
return -ENODEV;
}
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
fwd_xprt_info = rt_entry->xprt_info;
- mutex_lock(&fwd_xprt_info->tx_lock);
if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
- mutex_unlock(&fwd_xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
pr_err("%s: Discarding Command to route back\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto fwd_msg_out;
}
if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
- mutex_unlock(&fwd_xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
pr_err("%s: DST in the same cluster\n", __func__);
- return 0;
+ goto fwd_msg_out;
}
+ mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
- mutex_unlock(&fwd_xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
+fwd_msg_out:
+ up_read(&rt_entry->lock_lha4);
+ up_read(&routing_table_lock_lha3);
- return 0;
+ return ret;
}
static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
@@ -1268,14 +1242,14 @@
msg.cli.port_id = port_id;
if ((mode == SINGLE_LINK_MODE) && xprt_info) {
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
if (tmp_xprt_info != xprt_info)
continue;
msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
break;
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
} else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
broadcast_ctl_msg_locally(&msg);
} else if (mode == MULTI_LINK_MODE) {
@@ -1308,141 +1282,52 @@
return;
}
-static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
+static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info,
+ struct msm_ipc_router_remote_port *rport_ptr)
{
- struct msm_ipc_router_remote_port *rport_ptr;
-
- rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
- if (!rport_ptr) {
- pr_err("%s: No such remote port %08x:%08x\n",
- __func__, node_id, port_id);
- return;
- }
- mutex_lock(&rport_ptr->quota_lock);
- rport_ptr->restart_state = RESTART_PEND;
- msm_ipc_router_free_resume_tx_port(rport_ptr);
- mutex_unlock(&rport_ptr->quota_lock);
- return;
-}
-
-static void msm_ipc_cleanup_remote_server_info(
- struct msm_ipc_router_xprt_info *xprt_info)
-{
- struct msm_ipc_server *svr, *tmp_svr;
- struct msm_ipc_server_port *svr_port, *tmp_svr_port;
- int i;
union rr_control_msg ctl;
+ struct msm_ipc_server *server = rport_ptr->server;
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
-
+ D("Remove server %08x:%08x - %08x:%08x",
+ server->name.service, server->name.instance,
+ rport_ptr->node_id, rport_ptr->port_id);
ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
- mutex_lock(&server_list_lock);
- for (i = 0; i < SRV_HASH_SIZE; i++) {
- list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
- ctl.srv.service = svr->name.service;
- ctl.srv.instance = svr->name.instance;
- list_for_each_entry_safe(svr_port, tmp_svr_port,
- &svr->server_port_list, list) {
- if (svr_port->xprt_info != xprt_info)
- continue;
- D("Remove server %08x:%08x - %08x:%08x",
- ctl.srv.service, ctl.srv.instance,
- svr_port->server_addr.node_id,
- svr_port->server_addr.port_id);
- reset_remote_port_info(
- svr_port->server_addr.node_id,
- svr_port->server_addr.port_id);
- ctl.srv.node_id = svr_port->server_addr.node_id;
- ctl.srv.port_id = svr_port->server_addr.port_id;
- relay_ctl_msg(xprt_info, &ctl);
- broadcast_ctl_msg_locally(&ctl);
- platform_device_unregister(&svr_port->pdev);
- list_del(&svr_port->list);
- kfree(svr_port);
- }
- if (list_empty(&svr->server_port_list)) {
- list_del(&svr->list);
- kfree(svr);
- }
- }
- }
- mutex_unlock(&server_list_lock);
+ ctl.srv.service = server->name.service;
+ ctl.srv.instance = server->name.instance;
+ ctl.srv.node_id = rport_ptr->node_id;
+ ctl.srv.port_id = rport_ptr->port_id;
+ relay_ctl_msg(xprt_info, &ctl);
+ broadcast_ctl_msg_locally(&ctl);
+ msm_ipc_router_destroy_server(server,
+ rport_ptr->node_id, rport_ptr->port_id);
}
-static void msm_ipc_cleanup_remote_client_info(
- struct msm_ipc_router_xprt_info *xprt_info)
+static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info,
+ struct msm_ipc_routing_table_entry *rt_entry)
{
- struct msm_ipc_routing_table_entry *rt_entry;
- struct msm_ipc_router_remote_port *rport_ptr;
- int i, j;
- union rr_control_msg ctl;
-
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
-
- ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
- mutex_lock(&routing_table_lock);
- for (i = 0; i < RT_HASH_SIZE; i++) {
- list_for_each_entry(rt_entry, &routing_table[i], list) {
- mutex_lock(&rt_entry->lock);
- if (rt_entry->xprt_info != xprt_info) {
- mutex_unlock(&rt_entry->lock);
- continue;
- }
- for (j = 0; j < RP_HASH_SIZE; j++) {
- list_for_each_entry(rport_ptr,
- &rt_entry->remote_port_list[j], list) {
- if (rport_ptr->restart_state ==
- RESTART_PEND)
- continue;
- mutex_lock(&rport_ptr->quota_lock);
- rport_ptr->restart_state = RESTART_PEND;
- msm_ipc_router_free_resume_tx_port(
- rport_ptr);
- mutex_unlock(&rport_ptr->quota_lock);
- ctl.cli.node_id = rport_ptr->node_id;
- ctl.cli.port_id = rport_ptr->port_id;
- broadcast_ctl_msg_locally(&ctl);
- }
- }
- mutex_unlock(&rt_entry->lock);
- }
- }
- mutex_unlock(&routing_table_lock);
-}
-
-static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
-{
- struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
- int i, j;
+ union rr_control_msg ctl;
+ int j;
- mutex_lock(&routing_table_lock);
- for (i = 0; i < RT_HASH_SIZE; i++) {
- list_for_each_entry_safe(rt_entry, tmp_rt_entry,
- &routing_table[i], list) {
- mutex_lock(&rt_entry->lock);
- if (rt_entry->neighbor_node_id != node_id) {
- mutex_unlock(&rt_entry->lock);
- continue;
- }
- for (j = 0; j < RP_HASH_SIZE; j++) {
- list_for_each_entry_safe(rport_ptr,
- tmp_rport_ptr,
- &rt_entry->remote_port_list[j], list) {
- list_del(&rport_ptr->list);
- kfree(rport_ptr);
- }
- }
- mutex_unlock(&rt_entry->lock);
+ for (j = 0; j < RP_HASH_SIZE; j++) {
+ list_for_each_entry_safe(rport_ptr, tmp_rport_ptr,
+ &rt_entry->remote_port_list[j], list) {
+ list_del(&rport_ptr->list);
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
+ msm_ipc_router_free_resume_tx_port(rport_ptr);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
+
+ if (rport_ptr->server)
+ cleanup_rmt_server(xprt_info, rport_ptr);
+
+ ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+ ctl.cli.node_id = rport_ptr->node_id;
+ ctl.cli.port_id = rport_ptr->port_id;
+ relay_ctl_msg(xprt_info, &ctl);
+ broadcast_ctl_msg_locally(&ctl);
+ kfree(rport_ptr);
}
}
- mutex_unlock(&routing_table_lock);
}
static void msm_ipc_cleanup_routing_table(
@@ -1456,29 +1341,22 @@
return;
}
- mutex_lock(&routing_table_lock);
+ down_write(&server_list_lock_lha2);
+ down_write(&routing_table_lock_lha3);
for (i = 0; i < RT_HASH_SIZE; i++) {
list_for_each_entry(rt_entry, &routing_table[i], list) {
- mutex_lock(&rt_entry->lock);
- if (rt_entry->xprt_info == xprt_info)
- rt_entry->xprt_info = NULL;
- mutex_unlock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
+ if (rt_entry->xprt_info != xprt_info) {
+ up_write(&rt_entry->lock_lha4);
+ continue;
+ }
+ cleanup_rmt_ports(xprt_info, rt_entry);
+ rt_entry->xprt_info = NULL;
+ up_write(&rt_entry->lock_lha4);
}
}
- mutex_unlock(&routing_table_lock);
-}
-
-static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
-{
-
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
-
- msm_ipc_cleanup_remote_server_info(xprt_info);
- msm_ipc_cleanup_remote_client_info(xprt_info);
- msm_ipc_cleanup_routing_table(xprt_info);
+ up_write(&routing_table_lock_lha3);
+ up_write(&server_list_lock_lha2);
}
/**
@@ -1494,6 +1372,7 @@
struct msm_ipc_server_port *server_port;
struct msm_ipc_router_remote_port *rport_ptr = NULL;
+ down_read(&routing_table_lock_lha3);
list_for_each_entry(server_port, &server->server_port_list, list) {
rport_ptr = msm_ipc_router_lookup_remote_port(
server_port->server_addr.node_id,
@@ -1502,6 +1381,7 @@
continue;
rport_ptr->sec_rule = rule;
}
+ up_read(&routing_table_lock_lha3);
server->synced_sec_rule = 1;
}
@@ -1521,7 +1401,7 @@
int key = (service & (SRV_HASH_SIZE - 1));
struct msm_ipc_server *server;
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
list_for_each_entry(server, &server_list[key], list) {
if (server->name.service != service)
continue;
@@ -1540,7 +1420,7 @@
sync_sec_rule(server, rule);
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
}
/**
@@ -1558,7 +1438,7 @@
int key;
struct msm_ipc_server *server;
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
for (key = 0; key < SRV_HASH_SIZE; key++) {
list_for_each_entry(server, &server_list[key], list) {
if (server->synced_sec_rule)
@@ -1567,7 +1447,7 @@
sync_sec_rule(server, rule);
}
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
}
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
@@ -1590,25 +1470,22 @@
* 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);
+ down_write(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(hdr->src_node_id);
if (!rt_entry) {
rt_entry = alloc_routing_table_entry(hdr->src_node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
pr_err("%s: rt_entry allocation failed\n", __func__);
return -ENOMEM;
}
add_routing_table_entry(rt_entry);
}
- mutex_lock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
rt_entry->xprt_info = xprt_info;
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
-
- /* Cleanup any remote ports, if the node is coming out of reset */
- msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
+ up_write(&rt_entry->lock_lha4);
+ up_write(&routing_table_lock_lha3);
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
@@ -1624,8 +1501,8 @@
* Send list of servers from the local node and from nodes
* outside the mesh network in which this XPRT is part of.
*/
- mutex_lock(&server_list_lock);
- mutex_lock(&routing_table_lock);
+ down_read(&server_list_lock_lha2);
+ down_read(&routing_table_lock_lha3);
for (i = 0; i < RT_HASH_SIZE; i++) {
list_for_each_entry(rt_entry, &routing_table[i], list) {
if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
@@ -1636,14 +1513,14 @@
rc = msm_ipc_router_send_server_list(rt_entry->node_id,
xprt_info);
if (rc < 0) {
- mutex_unlock(&routing_table_lock);
- mutex_unlock(&server_list_lock);
+ up_read(&routing_table_lock_lha3);
+ up_read(&server_list_lock_lha2);
return rc;
}
}
}
- mutex_unlock(&routing_table_lock);
- mutex_unlock(&server_list_lock);
+ up_read(&routing_table_lock_lha3);
+ up_read(&server_list_lock_lha2);
RR("HELLO message processed\n");
return rc;
}
@@ -1652,19 +1529,26 @@
struct rr_packet *pkt)
{
struct msm_ipc_router_remote_port *rport_ptr;
+ int ret = 0;
RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+ down_read(&local_ports_lock_lha2);
+ down_read(&routing_table_lock_lha3);
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;
+ ret = -ENODEV;
+ goto prtm_out;
}
- mutex_lock(&rport_ptr->quota_lock);
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
rport_ptr->tx_quota_cnt = 0;
post_resume_tx(rport_ptr, pkt);
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
+prtm_out:
+ up_read(&routing_table_lock_lha3);
+ up_read(&local_ports_lock_lha2);
return 0;
}
@@ -1690,22 +1574,22 @@
* 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);
+ down_write(&routing_table_lock_lha3);
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);
+ up_write(&routing_table_lock_lha3);
pr_err("%s: rt_entry allocation failed\n", __func__);
return -ENOMEM;
}
- mutex_lock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
rt_entry->xprt_info = xprt_info;
- mutex_unlock(&rt_entry->lock);
+ up_write(&rt_entry->lock_lha4);
add_routing_table_entry(rt_entry);
}
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
/*
* If the service does not exist already in the database, create and
@@ -1713,7 +1597,7 @@
* the service is hosted and cache the security rule for the service
* in that remote port structure.
*/
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
if (!server) {
@@ -1721,25 +1605,29 @@
msg->srv.service, msg->srv.instance,
msg->srv.node_id, msg->srv.port_id, xprt_info);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server Create failed\n", __func__);
return -ENOMEM;
}
+ down_read(&routing_table_lock_lha3);
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);
+ up_read(&routing_table_lock_lha3);
+ up_write(&server_list_lock_lha2);
return -ENOMEM;
}
+ rport_ptr->server = server;
rport_ptr->sec_rule = msm_ipc_get_security_rule(
msg->srv.service,
msg->srv.instance);
}
+ up_read(&routing_table_lock_lha3);
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
/*
* Relay the new server message to other subsystems that do not belong
@@ -1758,7 +1646,7 @@
RR("o REMOVE_SERVER service=%08x:%d\n",
msg->srv.service, msg->srv.instance);
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
if (server) {
@@ -1772,7 +1660,7 @@
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
return 0;
}
@@ -1782,10 +1670,12 @@
struct msm_ipc_router_remote_port *rport_ptr;
RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+ down_write(&routing_table_lock_lha3);
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);
+ up_write(&routing_table_lock_lha3);
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
@@ -1920,19 +1810,19 @@
resume_tx_node_id = hdr->dst_node_id;
resume_tx_port_id = hdr->dst_port_id;
- rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
- hdr->src_port_id);
-
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
if (!port_ptr) {
pr_err("%s: No local port id %08x\n", __func__,
hdr->dst_port_id);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
release_pkt(pkt);
goto process_done;
}
+ down_read(&routing_table_lock_lha3);
+ rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+ hdr->src_port_id);
if (!rport_ptr) {
rport_ptr = msm_ipc_router_create_remote_port(
hdr->src_node_id,
@@ -1941,13 +1831,14 @@
pr_err("%s: Rmt Prt %08x:%08x create failed\n",
__func__, hdr->src_node_id,
hdr->src_port_id);
- mutex_unlock(&local_ports_lock);
+ up_read(&routing_table_lock_lha3);
+ up_read(&local_ports_lock_lha2);
goto process_done;
}
}
-
+ up_read(&routing_table_lock_lha3);
post_pkt_to_port(port_ptr, pkt, 0);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
process_done:
if (resume_tx) {
@@ -1983,13 +1874,13 @@
if (name->addrtype != MSM_IPC_ADDR_NAME)
return -EINVAL;
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(name->addr.port_name.service,
name->addr.port_name.instance,
IPC_ROUTER_NID_LOCAL,
port_ptr->this_port.port_id);
if (server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server already present\n", __func__);
return -EINVAL;
}
@@ -2000,7 +1891,7 @@
port_ptr->this_port.port_id,
NULL);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server Creation failed\n", __func__);
return -EINVAL;
}
@@ -2010,7 +1901,7 @@
ctl.srv.instance = server->name.instance;
ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
ctl.srv.port_id = port_ptr->this_port.port_id;
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = SERVER_PORT;
@@ -2042,13 +1933,13 @@
return -EINVAL;
}
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
port_ptr->port_name.instance,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server lookup failed\n", __func__);
return -ENODEV;
}
@@ -2060,7 +1951,7 @@
ctl.srv.port_id = port_ptr->this_port.port_id;
msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = CLIENT_PORT;
@@ -2111,11 +2002,11 @@
hdr->dst_port_id = port_id;
pkt->length += IPC_ROUTER_HDR_SIZE;
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(port_id);
if (!port_ptr) {
pr_err("%s: Local port %d not present\n", __func__, port_id);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
release_pkt(pkt);
return -ENODEV;
}
@@ -2123,7 +2014,7 @@
ret_len = pkt->length;
post_pkt_to_port(port_ptr, pkt, 0);
update_comm_mode_info(&src->mode_info, NULL);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
return ret_len;
}
@@ -2162,15 +2053,11 @@
hdr->dst_port_id = rport_ptr->port_id;
pkt->length += IPC_ROUTER_HDR_SIZE;
- mutex_lock(&rport_ptr->quota_lock);
- if (rport_ptr->restart_state != RESTART_NORMAL) {
- mutex_unlock(&rport_ptr->quota_lock);
- return -ENETRESET;
- }
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
if (msm_ipc_router_lookup_resume_tx_port(
rport_ptr, src->this_port.port_id)) {
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
return -EAGAIN;
}
resume_tx_port =
@@ -2179,7 +2066,7 @@
if (!resume_tx_port) {
pr_err("%s: Resume_Tx port allocation failed\n",
__func__);
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
return -ENOMEM;
}
INIT_LIST_HEAD(&resume_tx_port->list);
@@ -2187,29 +2074,26 @@
resume_tx_port->node_id = src->this_port.node_id;
list_add_tail(&resume_tx_port->list,
&rport_ptr->resume_tx_port_list);
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
return -EAGAIN;
}
rport_ptr->tx_quota_cnt++;
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
hdr->confirm_rx = 1;
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(hdr->dst_node_id);
if (!rt_entry || !rt_entry->xprt_info) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Remote node %d not up\n",
__func__, hdr->dst_node_id);
return -ENODEV;
}
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
xprt_info = rt_entry->xprt_info;
- mutex_lock(&xprt_info->tx_lock);
+ mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
- mutex_unlock(&xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ mutex_unlock(&xprt_info->tx_lock_lhb2);
+ up_read(&rt_entry->lock_lha4);
if (ret < 0) {
pr_err("%s: Write on XPRT failed\n", __func__);
@@ -2265,13 +2149,13 @@
dst_node_id = dest->addr.port_addr.node_id;
dst_port_id = dest->addr.port_addr.port_id;
} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
- mutex_lock(&server_list_lock);
+ down_read(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(
dest->addr.port_name.service,
dest->addr.port_name.instance,
0, 0);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
pr_err("%s: Destination not reachable\n", __func__);
return -ENODEV;
}
@@ -2280,16 +2164,18 @@
list);
dst_node_id = server_port->server_addr.node_id;
dst_port_id = server_port->server_addr.port_id;
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
}
if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
ret = loopback_data(src, dst_port_id, data);
return ret;
}
+ down_read(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
dst_port_id);
if (!rport_ptr) {
+ up_read(&routing_table_lock_lha3);
pr_err("%s: Remote port not found\n", __func__);
return -ENODEV;
}
@@ -2297,6 +2183,7 @@
if (src->check_send_permissions) {
ret = src->check_send_permissions(rport_ptr->sec_rule);
if (ret <= 0) {
+ up_read(&routing_table_lock_lha3);
pr_err("%s: permission failure for %s\n",
__func__, current->comm);
return -EPERM;
@@ -2305,11 +2192,13 @@
pkt = create_pkt(data);
if (!pkt) {
+ up_read(&routing_table_lock_lha3);
pr_err("%s: Pkt creation failed\n", __func__);
return -ENOMEM;
}
ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
+ up_read(&routing_table_lock_lha3);
release_pkt(pkt);
return ret;
@@ -2347,15 +2236,15 @@
if (!port_ptr || !data)
return -EINVAL;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
if (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return -EAGAIN;
}
pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return -ETOOSMALL;
}
list_del(&pkt->list);
@@ -2364,7 +2253,7 @@
*data = pkt->pkt_fragment_q;
ret = pkt->length;
kfree(pkt);
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return ret;
}
@@ -2384,9 +2273,9 @@
}
*data = NULL;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
while (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
if (timeout < 0) {
ret = wait_event_interruptible(
port_ptr->port_rx_wait_q,
@@ -2403,9 +2292,9 @@
}
if (timeout == 0)
return -ETIMEDOUT;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
ret = msm_ipc_router_read(port_ptr, data, 0);
if (ret <= 0 || !(*data))
@@ -2483,9 +2372,9 @@
return -EINVAL;
if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
if (port_ptr->type == SERVER_PORT) {
msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
@@ -2510,25 +2399,25 @@
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
} else if (port_ptr->type == CONTROL_PORT) {
- mutex_lock(&control_ports_lock);
+ down_write(&control_ports_lock_lha5);
list_del(&port_ptr->list);
- mutex_unlock(&control_ports_lock);
+ up_write(&control_ports_lock_lha5);
} else if (port_ptr->type == IRSC_PORT) {
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
signal_irsc_completion();
}
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
list_del(&pkt->list);
release_pkt(pkt);
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
if (port_ptr->type == SERVER_PORT) {
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(
port_ptr->port_name.service,
port_ptr->port_name.instance,
@@ -2538,7 +2427,7 @@
msm_ipc_router_destroy_server(server,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
}
wake_lock_destroy(&port_ptr->port_rx_wake_lock);
@@ -2554,13 +2443,13 @@
if (!port_ptr)
return -EINVAL;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
if (!list_empty(&port_ptr->port_rx_q)) {
pkt = list_first_entry(&port_ptr->port_rx_q,
struct rr_packet, list);
rc = pkt->length;
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return rc;
}
@@ -2570,13 +2459,13 @@
if (!port_ptr)
return -EINVAL;
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
port_ptr->type = CONTROL_PORT;
- mutex_lock(&control_ports_lock);
+ down_write(&control_ports_lock_lha5);
list_add_tail(&port_ptr->list, &control_ports);
- mutex_unlock(&control_ports_lock);
+ up_write(&control_ports_lock_lha5);
return 0;
}
@@ -2600,7 +2489,7 @@
return -EINVAL;
}
- mutex_lock(&server_list_lock);
+ down_read(&server_list_lock_lha2);
if (!lookup_mask)
lookup_mask = 0xFFFFFFFF;
key = (srv_name->service & (SRV_HASH_SIZE - 1));
@@ -2623,7 +2512,7 @@
i++;
}
}
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
return i;
}
@@ -2632,14 +2521,14 @@
{
struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
- mutex_lock(&xprt_info_list_lock);
+ down_write(&xprt_info_list_lock_lha5);
list_for_each_entry_safe(xprt_info, tmp_xprt_info,
&xprt_info_list, list) {
xprt_info->xprt->close(xprt_info->xprt);
list_del(&xprt_info->list);
kfree(xprt_info);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_write(&xprt_info_list_lock_lha5);
return 0;
}
@@ -2650,9 +2539,9 @@
struct msm_ipc_routing_table_entry *rt_entry;
for (j = 0; j < RT_HASH_SIZE; j++) {
- mutex_lock(&routing_table_lock);
+ down_read(&routing_table_lock_lha3);
list_for_each_entry(rt_entry, &routing_table[j], list) {
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
i += scnprintf(buf + i, max - i,
"Node Id: 0x%08x\n", rt_entry->node_id);
if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
@@ -2669,9 +2558,9 @@
rt_entry->xprt_info->remote_node_id);
}
i += scnprintf(buf + i, max - i, "\n");
- mutex_unlock(&rt_entry->lock);
+ up_read(&rt_entry->lock_lha4);
}
- mutex_unlock(&routing_table_lock);
+ up_read(&routing_table_lock_lha3);
}
return i;
@@ -2682,7 +2571,7 @@
int i = 0;
struct msm_ipc_router_xprt_info *xprt_info;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(xprt_info, &xprt_info_list, list) {
i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
xprt_info->xprt->name);
@@ -2694,7 +2583,7 @@
xprt_info->remote_node_id);
i += scnprintf(buf + i, max - i, "\n");
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return i;
}
@@ -2705,7 +2594,7 @@
struct msm_ipc_server *server;
struct msm_ipc_server_port *server_port;
- mutex_lock(&server_list_lock);
+ down_read(&server_list_lock_lha2);
for (j = 0; j < SRV_HASH_SIZE; j++) {
list_for_each_entry(server, &server_list[j], list) {
list_for_each_entry(server_port,
@@ -2725,7 +2614,7 @@
}
}
}
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
return i;
}
@@ -2737,9 +2626,9 @@
struct msm_ipc_routing_table_entry *rt_entry;
for (j = 0; j < RT_HASH_SIZE; j++) {
- mutex_lock(&routing_table_lock);
+ down_read(&routing_table_lock_lha3);
list_for_each_entry(rt_entry, &routing_table[j], list) {
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
for (k = 0; k < RP_HASH_SIZE; k++) {
list_for_each_entry(rport_ptr,
&rt_entry->remote_port_list[k],
@@ -2756,9 +2645,9 @@
i += scnprintf(buf + i, max - i, "\n");
}
}
- mutex_unlock(&rt_entry->lock);
+ up_read(&rt_entry->lock_lha4);
}
- mutex_unlock(&routing_table_lock);
+ up_read(&routing_table_lock_lha3);
}
return i;
@@ -2769,7 +2658,7 @@
int i = 0;
struct msm_ipc_port *port_ptr;
- mutex_lock(&control_ports_lock);
+ down_read(&control_ports_lock_lha5);
list_for_each_entry(port_ptr, &control_ports, list) {
i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
port_ptr->this_port.node_id);
@@ -2777,7 +2666,7 @@
port_ptr->this_port.port_id);
i += scnprintf(buf + i, max - i, "\n");
}
- mutex_unlock(&control_ports_lock);
+ up_read(&control_ports_lock_lha5);
return i;
}
@@ -2788,7 +2677,7 @@
unsigned long flags;
struct msm_ipc_port *port_ptr;
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
for (j = 0; j < LP_HASH_SIZE; j++) {
list_for_each_entry(port_ptr, &local_ports[j], list) {
spin_lock_irqsave(&port_ptr->port_lock, flags);
@@ -2808,7 +2697,7 @@
i += scnprintf(buf + i, max - i, "\n");
}
}
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
return i;
}
@@ -2882,8 +2771,8 @@
xprt_info->initialized = 0;
xprt_info->remote_node_id = -1;
INIT_LIST_HEAD(&xprt_info->pkt_list);
- mutex_init(&xprt_info->rx_lock);
- mutex_init(&xprt_info->tx_lock);
+ mutex_init(&xprt_info->rx_lock_lhb2);
+ mutex_init(&xprt_info->tx_lock_lhb2);
wake_lock_init(&xprt_info->wakelock,
WAKE_LOCK_SUSPEND, xprt->name);
xprt_info->need_len = 0;
@@ -2902,18 +2791,18 @@
xprt_info->initialized = 1;
}
- mutex_lock(&xprt_info_list_lock);
+ down_write(&xprt_info_list_lock_lha5);
list_add_tail(&xprt_info->list, &xprt_info_list);
- mutex_unlock(&xprt_info_list_lock);
+ up_write(&xprt_info_list_lock_lha5);
- mutex_lock(&routing_table_lock);
+ down_write(&routing_table_lock_lha3);
if (!routing_table_inited) {
init_routing_table();
rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
add_routing_table_entry(rt_entry);
routing_table_inited = 1;
}
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
xprt->priv = xprt_info;
@@ -2927,13 +2816,13 @@
if (xprt && xprt->priv) {
xprt_info = xprt->priv;
- mutex_lock(&xprt_info->rx_lock);
+ mutex_lock(&xprt_info->rx_lock_lhb2);
xprt_info->abort_data_read = 1;
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
- mutex_lock(&xprt_info_list_lock);
+ down_write(&xprt_info_list_lock_lha5);
list_del(&xprt_info->list);
- mutex_unlock(&xprt_info_list_lock);
+ up_write(&xprt_info_list_lock_lha5);
flush_workqueue(xprt_info->workqueue);
destroy_workqueue(xprt_info->workqueue);
@@ -2964,7 +2853,7 @@
struct msm_ipc_router_xprt_work *xprt_work =
container_of(work, struct msm_ipc_router_xprt_work, work);
- modem_reset_cleanup(xprt_work->xprt->priv);
+ msm_ipc_cleanup_routing_table(xprt_work->xprt->priv);
msm_ipc_router_remove_xprt(xprt_work->xprt);
if (atomic_dec_return(&pending_close_count) == 0)
@@ -3034,10 +2923,10 @@
if (!pkt)
return;
- mutex_lock(&xprt_info->rx_lock);
+ mutex_lock(&xprt_info->rx_lock_lhb2);
list_add_tail(&pkt->list, &xprt_info->pkt_list);
wake_lock(&xprt_info->wakelock);
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
queue_work(xprt_info->workqueue, &xprt_info->read_data);
}
@@ -3105,14 +2994,14 @@
for (i = 0; i < LP_HASH_SIZE; i++)
INIT_LIST_HEAD(&local_ports[i]);
- mutex_lock(&routing_table_lock);
+ down_write(&routing_table_lock_lha3);
if (!routing_table_inited) {
init_routing_table();
rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
add_routing_table_entry(rt_entry);
routing_table_inited = 1;
}
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
init_waitqueue_head(&subsystem_restart_wait);
ret = msm_ipc_router_init_sockets();
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 64d8fed..515dc92 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -55,6 +55,10 @@
} \
} while (0) \
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
static int sockets_enabled;
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
@@ -264,7 +268,6 @@
{
struct sock *sk;
struct msm_ipc_port *port_ptr;
- void *pil;
if (unlikely(protocol != 0)) {
pr_err("%s: Protocol not supported\n", __func__);
@@ -297,9 +300,7 @@
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
- pil = msm_ipc_load_default_node();
msm_ipc_sk(sk)->port = port_ptr;
- msm_ipc_sk(sk)->default_pil = pil;
return 0;
}
@@ -311,6 +312,7 @@
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr;
int ret;
+ void *pil;
if (!sk)
return -EINVAL;
@@ -340,6 +342,8 @@
if (!port_ptr)
return -ENODEV;
+ pil = msm_ipc_load_default_node();
+ msm_ipc_sk(sk)->default_pil = pil;
lock_sock(sk);
ret = msm_ipc_router_register_server(port_ptr, &addr->address);
@@ -407,9 +411,9 @@
lock_sock(sk);
timeout = sk->sk_rcvtimeo;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
while (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
release_sock(sk);
if (timeout < 0) {
ret = wait_event_interruptible(
@@ -431,9 +435,9 @@
return 0;
}
lock_sock(sk);
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
if (ret <= 0 || !msg) {
@@ -458,8 +462,10 @@
struct msm_ipc_port *port_ptr;
struct server_lookup_args server_arg;
struct msm_ipc_server_info *srv_info = NULL;
- unsigned int n, srv_info_sz = 0;
+ unsigned int n;
+ size_t srv_info_sz = 0;
int ret;
+ void *pil;
if (!sk)
return -EINVAL;
@@ -487,6 +493,8 @@
break;
case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
+ pil = msm_ipc_load_default_node();
+ msm_ipc_sk(sk)->default_pil = pil;
ret = copy_from_user(&server_arg, (void *)arg,
sizeof(server_arg));
if (ret) {
@@ -499,16 +507,16 @@
break;
}
if (server_arg.num_entries_in_array) {
- srv_info_sz = server_arg.num_entries_in_array *
- sizeof(*srv_info);
- if ((srv_info_sz / sizeof(*srv_info)) !=
- server_arg.num_entries_in_array) {
+ if (server_arg.num_entries_in_array >
+ (SIZE_MAX / sizeof(*srv_info))) {
pr_err("%s: Integer Overflow %d * %d\n",
__func__, sizeof(*srv_info),
server_arg.num_entries_in_array);
ret = -EINVAL;
break;
}
+ srv_info_sz = server_arg.num_entries_in_array *
+ sizeof(*srv_info);
srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
if (!srv_info) {
ret = -ENOMEM;
@@ -585,7 +593,8 @@
lock_sock(sk);
ret = msm_ipc_router_close_port(port_ptr);
- msm_ipc_unload_default_node(pil);
+ if (pil)
+ msm_ipc_unload_default_node(pil);
release_sock(sk);
sock_put(sk);
sock->sk = NULL;
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index c8d6d5a..e43a0e27 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.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
@@ -28,6 +28,7 @@
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
+#include <linux/clk.h>
#include <linux/mfd/pmic8058.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
@@ -38,26 +39,24 @@
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "devices.h"
+#include "clock.h"
#include "mdm_private.h"
#define MDM_PBLRDY_CNT 20
static int mdm_debug_mask;
-static int power_on_count;
-static int hsic_peripheral_status;
-static DEFINE_MUTEX(hsic_status_lock);
static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
{
if (!mdm_drv->pdata->peripheral_platform_device)
return;
- mutex_lock(&hsic_status_lock);
- if (hsic_peripheral_status)
+ mutex_lock(&mdm_drv->peripheral_status_lock);
+ if (mdm_drv->peripheral_status)
goto out;
platform_device_add(mdm_drv->pdata->peripheral_platform_device);
- hsic_peripheral_status = 1;
+ mdm_drv->peripheral_status = 1;
out:
- mutex_unlock(&hsic_status_lock);
+ mutex_unlock(&mdm_drv->peripheral_status_lock);
}
static void mdm_peripheral_disconnect(struct mdm_modem_drv *mdm_drv)
@@ -65,13 +64,13 @@
if (!mdm_drv->pdata->peripheral_platform_device)
return;
- mutex_lock(&hsic_status_lock);
- if (!hsic_peripheral_status)
+ mutex_lock(&mdm_drv->peripheral_status_lock);
+ if (!mdm_drv->peripheral_status)
goto out;
platform_device_del(mdm_drv->pdata->peripheral_platform_device);
- hsic_peripheral_status = 0;
+ mdm_drv->peripheral_status = 0;
out:
- mutex_unlock(&hsic_status_lock);
+ mutex_unlock(&mdm_drv->peripheral_status_lock);
}
/* This function can be called from atomic context. */
@@ -112,8 +111,8 @@
for (i = 20; i > 0; i--) {
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
- pr_info("%s: mdm2ap_status went low, i = %d\n",
- __func__, i);
+ pr_debug("%s:id %d: mdm2ap_statuswent low, i=%d\n",
+ __func__, mdm_drv->device_id, i);
break;
}
msleep(100);
@@ -123,8 +122,10 @@
gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
soft_reset_direction);
if (i == 0) {
- pr_err("%s: MDM2AP_STATUS never went low. Doing a hard reset\n",
- __func__);
+ pr_debug("%s:id %d: MDM2AP_STATUS never went low. Doing a hard reset\n",
+ __func__, mdm_drv->device_id);
+ gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+ soft_reset_direction);
/*
* Currently, there is a debounce timer on the charm PMIC. It is
* necessary to hold the PMIC RESET low for ~3.5 seconds
@@ -139,13 +140,14 @@
{
int i;
int pblrdy;
- if (power_on_count != 1) {
- pr_err("%s: Calling fn when power_on_count != 1\n",
- __func__);
+ if (mdm_drv->power_on_count != 1) {
+ pr_debug("%s:id %d: Calling fn when power_on_count != 1\n",
+ __func__, mdm_drv->device_id);
return;
}
- pr_err("%s: Powering on modem for the first time\n", __func__);
+ pr_debug("%s:id %d: Powering on modem for the first time\n",
+ __func__, mdm_drv->device_id);
mdm_peripheral_disconnect(mdm_drv);
/* If this is the first power-up after a panic, the modem may still
@@ -159,13 +161,15 @@
/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
* then pull it back low.
*/
- pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
+ pr_debug("%s:id %d: Pulling AP2MDM_KPDPWR gpio high\n",
+ __func__, mdm_drv->device_id);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
msleep(1000);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
- } else
+ } else {
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+ }
if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
goto start_mdm_peripheral;
@@ -176,7 +180,8 @@
break;
usleep_range(5000, 5000);
}
- pr_debug("%s: i:%d\n", __func__, i);
+ pr_debug("%s: id %d: pblrdy i:%d\n", __func__,
+ mdm_drv->device_id, i);
start_mdm_peripheral:
mdm_peripheral_connect(mdm_drv);
@@ -188,7 +193,8 @@
int i;
int pblrdy;
- pr_err("%s: soft resetting mdm modem\n", __func__);
+ pr_debug("%s: id %d: soft resetting mdm modem\n",
+ __func__, mdm_drv->device_id);
mdm_peripheral_disconnect(mdm_drv);
mdm_toggle_soft_reset(mdm_drv);
@@ -202,7 +208,8 @@
usleep_range(5000, 5000);
}
- pr_debug("%s: i:%d\n", __func__, i);
+ pr_debug("%s: id %d: pblrdy i:%d\n", __func__,
+ mdm_drv->device_id, i);
start_mdm_peripheral:
mdm_peripheral_connect(mdm_drv);
@@ -211,7 +218,7 @@
static void mdm_power_on_common(struct mdm_modem_drv *mdm_drv)
{
- power_on_count++;
+ mdm_drv->power_on_count++;
/* this gpio will be used to indicate apq readiness,
* de-assert it now so that it can be asserted later.
@@ -226,10 +233,10 @@
* user space but we're already powered on. Ignore it.
*/
if (mdm_drv->pdata->early_power_on &&
- (power_on_count == 2))
+ (mdm_drv->power_on_count == 2))
return;
- if (power_on_count == 1)
+ if (mdm_drv->power_on_count == 1)
mdm_do_first_power_on(mdm_drv);
else
mdm_do_soft_power_on(mdm_drv);
@@ -242,7 +249,8 @@
static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
{
- pr_debug("%s: value:%d\n", __func__, value);
+ pr_debug("%s: id %d: value:%d\n", __func__,
+ value, mdm_drv->device_id);
if (value) {
mdm_peripheral_disconnect(mdm_drv);
@@ -256,13 +264,15 @@
{
switch (type) {
case APQ_CONTROLLED_UPGRADE:
- pr_debug("%s APQ controlled modem image upgrade\n", __func__);
- mdm_drv->mdm_ready = 0;
+ pr_debug("%s: id %d: APQ controlled modem image upgrade\n",
+ __func__, mdm_drv->device_id);
+ atomic_set(&mdm_drv->mdm_ready, 0);
mdm_toggle_soft_reset(mdm_drv);
break;
case MDM_CONTROLLED_UPGRADE:
- pr_debug("%s MDM controlled modem image upgrade\n", __func__);
- mdm_drv->mdm_ready = 0;
+ pr_debug("%s: id %d: MDM controlled modem image upgrade\n",
+ __func__, mdm_drv->device_id);
+ atomic_set(&mdm_drv->mdm_ready, 0);
/*
* If we have no image currently present on the modem, then we
* would be in PBL, in which case the status gpio would not go
@@ -270,15 +280,19 @@
*/
mdm_drv->disable_status_check = 1;
if (GPIO_IS_VALID(mdm_drv->usb_switch_gpio)) {
- pr_info("%s Switching usb control to MDM\n", __func__);
+ pr_debug("%s: id %d: Switching usb control to MDM\n",
+ __func__, mdm_drv->device_id);
gpio_direction_output(mdm_drv->usb_switch_gpio, 1);
} else
- pr_err("%s usb switch gpio unavailable\n", __func__);
+ pr_err("%s: id %d: usb switch gpio unavailable\n",
+ __func__, mdm_drv->device_id);
break;
default:
- pr_err("%s invalid upgrade type\n", __func__);
+ pr_err("%s: id %d: invalid upgrade type\n",
+ __func__, mdm_drv->device_id);
}
}
+
static struct mdm_ops mdm_cb = {
.power_on_mdm_cb = mdm_power_on_common,
.reset_mdm_cb = mdm_power_on_common,
@@ -289,44 +303,10 @@
.image_upgrade_cb = mdm_image_upgrade,
};
-static int __init mdm_modem_probe(struct platform_device *pdev)
+int mdm_get_ops(struct mdm_ops **mdm_ops)
{
- return mdm_common_create(pdev, &mdm_cb);
+ *mdm_ops = &mdm_cb;
+ return 0;
}
-static int __devexit mdm_modem_remove(struct platform_device *pdev)
-{
- return mdm_common_modem_remove(pdev);
-}
-static void mdm_modem_shutdown(struct platform_device *pdev)
-{
- mdm_common_modem_shutdown(pdev);
-}
-
-static struct platform_driver mdm_modem_driver = {
- .remove = mdm_modem_remove,
- .shutdown = mdm_modem_shutdown,
- .driver = {
- .name = "mdm2_modem",
- .owner = THIS_MODULE
- },
-};
-
-static int __init mdm_modem_init(void)
-{
- return platform_driver_probe(&mdm_modem_driver, mdm_modem_probe);
-}
-
-static void __exit mdm_modem_exit(void)
-{
- platform_driver_unregister(&mdm_modem_driver);
-}
-
-module_init(mdm_modem_init);
-module_exit(mdm_modem_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("mdm modem driver");
-MODULE_VERSION("2.0");
-MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index de46be8..5e12a0d 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -49,22 +49,15 @@
#define MDM_RDUMP_TIMEOUT 120000L
#define MDM2AP_STATUS_TIMEOUT_MS 60000L
-static unsigned int mdm_debug_mask;
-static struct workqueue_struct *mdm_queue;
-static struct workqueue_struct *mdm_sfr_queue;
-static unsigned int dump_timeout_ms;
-static int vddmin_gpios_sent;
-
+/* Allow a maximum device id of this many digits */
+#define MAX_DEVICE_DIGITS 10
#define EXTERNAL_MODEM "external_modem"
+#define SUBSYS_NAME_LENGTH \
+ (sizeof(EXTERNAL_MODEM) + MAX_DEVICE_DIGITS)
-static struct mdm_modem_drv *mdm_drv;
-static struct subsys_device *mdm_subsys_dev;
-
-DECLARE_COMPLETION(mdm_needs_reload);
-DECLARE_COMPLETION(mdm_boot);
-DECLARE_COMPLETION(mdm_ram_dumps);
-
-static int first_boot = 1;
+#define DEVICE_BASE_NAME "mdm"
+#define DEVICE_NAME_LENGTH \
+ (sizeof(DEVICE_BASE_NAME) + MAX_DEVICE_DIGITS)
#define RD_BUF_SIZE 100
#define SFR_MAX_RETRIES 10
@@ -74,58 +67,211 @@
GPIO_UPDATE_BOOTING_CONFIG = 1,
GPIO_UPDATE_RUNNING_CONFIG,
};
-static int mdm2ap_status_valid_old_config;
-static struct gpiomux_setting mdm2ap_status_old_config;
+
+struct mdm_device {
+ struct list_head link;
+ struct mdm_modem_drv mdm_data;
+
+ int mdm2ap_status_valid_old_config;
+ struct gpiomux_setting mdm2ap_status_old_config;
+ int first_boot;
+ struct workqueue_struct *mdm_queue;
+ struct workqueue_struct *mdm_sfr_queue;
+ unsigned int dump_timeout_ms;
+
+ char subsys_name[SUBSYS_NAME_LENGTH];
+ struct subsys_desc mdm_subsys;
+ struct subsys_device *mdm_subsys_dev;
+
+ char device_name[DEVICE_NAME_LENGTH];
+ struct miscdevice misc_device;
+
+ struct completion mdm_needs_reload;
+ struct completion mdm_boot;
+ struct completion mdm_ram_dumps;
+ int mdm_errfatal_irq;
+ int mdm_status_irq;
+ int mdm_pblrdy_irq;
+
+ struct delayed_work mdm2ap_status_check_work;
+ struct work_struct mdm_status_work;
+ struct work_struct sfr_reason_work;
+
+ struct notifier_block mdm_panic_blk;
+
+ int ssr_started_internally;
+};
+
+static struct list_head mdm_devices;
+static DEFINE_SPINLOCK(mdm_devices_lock);
+
+static int ssr_count;
+static DEFINE_SPINLOCK(ssr_lock);
+
+static unsigned int mdm_debug_mask;
+int vddmin_gpios_sent;
+static struct mdm_ops *mdm_ops;
+
+static void mdm_device_list_add(struct mdm_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdm_devices_lock, flags);
+ list_add_tail(&mdev->link, &mdm_devices);
+ spin_unlock_irqrestore(&mdm_devices_lock, flags);
+}
+
+static void mdm_device_list_remove(struct mdm_device *mdev)
+{
+ unsigned long flags;
+ struct mdm_device *lmdev, *tmp;
+
+ spin_lock_irqsave(&mdm_devices_lock, flags);
+ list_for_each_entry_safe(lmdev, tmp, &mdm_devices, link) {
+ if (mdev && mdev == lmdev) {
+ pr_debug("%s: removing device id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ list_del(&mdev->link);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&mdm_devices_lock, flags);
+}
+
+/* If the platform's cascading_ssr flag is set, the subsystem
+ * restart module will restart the other modems so stop
+ * monitoring them as well.
+ * This function can be called from interrupt context.
+ */
+static void mdm_start_ssr(struct mdm_device *mdev)
+{
+ unsigned long flags;
+ int start_ssr = 1;
+
+ spin_lock_irqsave(&ssr_lock, flags);
+ if (mdev->mdm_data.pdata->cascading_ssr &&
+ ssr_count > 0) {
+ start_ssr = 0;
+ } else {
+ ssr_count++;
+ mdev->ssr_started_internally = 1;
+ }
+ spin_unlock_irqrestore(&ssr_lock, flags);
+
+ if (start_ssr) {
+ atomic_set(&mdev->mdm_data.mdm_ready, 0);
+ pr_debug("%s: Resetting mdm id %d due to mdm error\n",
+ __func__, mdev->mdm_data.device_id);
+ subsystem_restart_dev(mdev->mdm_subsys_dev);
+ } else {
+ pr_debug("%s: Another modem is already in SSR\n",
+ __func__);
+ }
+}
+
+/* Increment the reference count to handle the case where
+ * subsystem restart is initiated by the SSR service.
+ */
+static void mdm_ssr_started(struct mdm_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ssr_lock, flags);
+ ssr_count++;
+ atomic_set(&mdev->mdm_data.mdm_ready, 0);
+ spin_unlock_irqrestore(&ssr_lock, flags);
+}
+
+/* mdm_ssr_completed assumes that mdm_ssr_started has previously
+ * been called.
+ */
+static void mdm_ssr_completed(struct mdm_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ssr_lock, flags);
+ ssr_count--;
+ if (mdev->ssr_started_internally) {
+ mdev->ssr_started_internally = 0;
+ ssr_count--;
+ }
+
+ if (ssr_count < 0) {
+ pr_err("%s: ssr_count = %d\n",
+ __func__, ssr_count);
+ panic("%s: ssr_count = %d < 0\n",
+ __func__, ssr_count);
+ }
+ spin_unlock_irqrestore(&ssr_lock, flags);
+}
static irqreturn_t mdm_vddmin_change(int irq, void *dev_id)
{
- int value = gpio_get_value(
- mdm_drv->pdata->vddmin_resource->mdm2ap_vddmin_gpio);
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ struct mdm_vddmin_resource *vddmin_res;
+ int value;
+ if (!mdev)
+ goto handled;
+
+ vddmin_res = mdev->mdm_data.pdata->vddmin_resource;
+ if (!vddmin_res)
+ goto handled;
+
+ value = gpio_get_value(
+ vddmin_res->mdm2ap_vddmin_gpio);
if (value == 0)
- pr_info("External Modem entered Vddmin\n");
+ pr_debug("External Modem id %d entered Vddmin\n",
+ mdev->mdm_data.device_id);
else
- pr_info("External Modem exited Vddmin\n");
-
+ pr_debug("External Modem id %d exited Vddmin\n",
+ mdev->mdm_data.device_id);
+handled:
return IRQ_HANDLED;
}
+/* The vddmin_res resource may not be supported by some platforms. */
static void mdm_setup_vddmin_gpios(void)
{
+ unsigned long flags;
struct msm_rpm_iv_pair req;
+ struct mdm_device *mdev;
struct mdm_vddmin_resource *vddmin_res;
int irq, ret;
- /* This resource may not be supported by some platforms. */
- vddmin_res = mdm_drv->pdata->vddmin_resource;
- if (!vddmin_res)
- return;
+ spin_lock_irqsave(&mdm_devices_lock, flags);
+ list_for_each_entry(mdev, &mdm_devices, link) {
+ vddmin_res = mdev->mdm_data.pdata->vddmin_resource;
+ if (!vddmin_res)
+ continue;
- pr_info("Enabling vddmin logging\n");
- req.id = vddmin_res->rpm_id;
- req.value = ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
- << 16;
- req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
- req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
+ pr_debug("Enabling vddmin logging on modem id %d\n",
+ mdev->mdm_data.device_id);
+ req.id = vddmin_res->rpm_id;
+ req.value =
+ ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
+ << 16;
+ req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
+ req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
- msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
+ msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
- /* Start monitoring low power gpio from mdm */
- irq = MSM_GPIO_TO_INT(vddmin_res->mdm2ap_vddmin_gpio);
- if (irq < 0) {
- pr_err("%s: could not get LPM POWER IRQ resource.\n",
- __func__);
- goto error_end;
+ /* Start monitoring low power gpio from mdm */
+ irq = gpio_to_irq(vddmin_res->mdm2ap_vddmin_gpio);
+ if (irq < 0)
+ pr_err("%s: could not get LPM POWER IRQ resource mdm id %d.\n",
+ __func__, mdev->mdm_data.device_id);
+ else {
+ ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "mdm lpm", mdev);
+
+ if (ret < 0)
+ pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
+ __func__, irq, ret);
+ }
}
-
- ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "mdm lpm", NULL);
-
- if (ret < 0)
- pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
- __func__, irq, ret);
-error_end:
+ spin_unlock_irqrestore(&mdm_devices_lock, flags);
return;
}
@@ -133,48 +279,53 @@
{
int ret, ntries = 0;
char sfr_buf[RD_BUF_SIZE];
+ struct mdm_platform_data *pdata;
+ struct mdm_device *mdev = container_of(work,
+ struct mdm_device, sfr_reason_work);
- do {
- msleep(SFR_RETRY_INTERVAL);
- ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+ pdata = mdev->mdm_data.pdata;
+ if (pdata->sysmon_subsys_id_valid) {
+ do {
+ ret = sysmon_get_reason(pdata->sysmon_subsys_id,
sfr_buf, sizeof(sfr_buf));
- if (ret) {
- /*
- * The sysmon device may not have been probed as yet
- * after the restart.
+ if (!ret) {
+ pr_err("mdm restart reason: %s\n", sfr_buf);
+ return;
+ }
+ /* Wait for the modem to be fully booted after a
+ * subsystem restart. This may take several seconds.
*/
- pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
- "%d/%d tries\n", __func__, ret,
- ntries + 1, SFR_MAX_RETRIES);
- } else {
- pr_err("mdm restart reason: %s\n", sfr_buf);
- break;
- }
- } while (++ntries < SFR_MAX_RETRIES);
+ msleep(SFR_RETRY_INTERVAL);
+ } while (++ntries < SFR_MAX_RETRIES);
+ pr_debug("%s: Error retrieving restart reason: %d\n",
+ __func__, ret);
+ }
}
-static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
-
static void mdm2ap_status_check(struct work_struct *work)
{
+ struct mdm_device *mdev =
+ container_of(work, struct mdm_device,
+ mdm2ap_status_check_work.work);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
/*
* If the mdm modem did not pull the MDM2AP_STATUS gpio
* high then call subsystem_restart.
*/
if (!mdm_drv->disable_status_check) {
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
- pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
- __func__);
- mdm_drv->mdm_ready = 0;
- subsystem_restart_dev(mdm_subsys_dev);
+ pr_debug("%s: MDM2AP_STATUS did not go high on mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_start_ssr(mdev);
}
}
}
-static DECLARE_DELAYED_WORK(mdm2ap_status_check_work, mdm2ap_status_check);
-
-static void mdm_update_gpio_configs(enum gpio_update_config gpio_config)
+static void mdm_update_gpio_configs(struct mdm_device *mdev,
+ enum gpio_update_config gpio_config)
{
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
/* Some gpio configuration may need updating after modem bootup.*/
switch (gpio_config) {
case GPIO_UPDATE_RUNNING_CONFIG:
@@ -182,20 +333,20 @@
if (msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
GPIOMUX_ACTIVE,
mdm_drv->pdata->mdm2ap_status_gpio_run_cfg,
- &mdm2ap_status_old_config))
- pr_err("%s: failed updating running gpio config\n",
- __func__);
+ &mdev->mdm2ap_status_old_config))
+ pr_err("%s: failed updating running gpio config mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
else
- mdm2ap_status_valid_old_config = 1;
+ mdev->mdm2ap_status_valid_old_config = 1;
}
break;
case GPIO_UPDATE_BOOTING_CONFIG:
- if (mdm2ap_status_valid_old_config) {
+ if (mdev->mdm2ap_status_valid_old_config) {
msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
GPIOMUX_ACTIVE,
- &mdm2ap_status_old_config,
+ &mdev->mdm2ap_status_old_config,
NULL);
- mdm2ap_status_valid_old_config = 0;
+ mdev->mdm2ap_status_valid_old_config = 0;
}
break;
default:
@@ -204,21 +355,27 @@
}
}
-long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
+static long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int status, ret = 0;
+ struct mdm_device *mdev = filp->private_data;
+ struct mdm_modem_drv *mdm_drv;
if (_IOC_TYPE(cmd) != CHARM_CODE) {
- pr_err("%s: invalid ioctl code\n", __func__);
+ pr_err("%s: invalid ioctl code to mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
return -EINVAL;
}
- pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+ mdm_drv = &mdev->mdm_data;
+ pr_debug("%s: Entering ioctl cmd = %d, mdm id = %d\n",
+ __func__, _IOC_NR(cmd), mdev->mdm_data.device_id);
switch (cmd) {
case WAKE_CHARM:
- pr_info("%s: Powering on mdm\n", __func__);
- mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+ pr_debug("%s: Powering on mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_ops->power_on_mdm_cb(mdm_drv);
break;
case CHECK_FOR_BOOT:
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
@@ -227,30 +384,33 @@
put_user(0, (unsigned long __user *) arg);
break;
case NORMAL_BOOT_DONE:
- pr_debug("%s: check if mdm is booted up\n", __func__);
+ pr_debug("%s: check if mdm id %d is booted up\n",
+ __func__, mdev->mdm_data.device_id);
get_user(status, (unsigned long __user *) arg);
if (status) {
- pr_debug("%s: normal boot failed\n", __func__);
+ pr_debug("%s: normal boot of mdm id %d failed\n",
+ __func__, mdev->mdm_data.device_id);
mdm_drv->mdm_boot_status = -EIO;
} else {
- pr_info("%s: normal boot done\n", __func__);
+ pr_debug("%s: normal boot of mdm id %d done\n",
+ __func__, mdev->mdm_data.device_id);
mdm_drv->mdm_boot_status = 0;
}
- mdm_drv->mdm_ready = 1;
+ atomic_set(&mdm_drv->mdm_ready, 1);
- if (mdm_drv->ops->normal_boot_done_cb != NULL)
- mdm_drv->ops->normal_boot_done_cb(mdm_drv);
+ if (mdm_ops->normal_boot_done_cb != NULL)
+ mdm_ops->normal_boot_done_cb(mdm_drv);
- if (!first_boot)
- complete(&mdm_boot);
+ if (!mdev->first_boot)
+ complete(&mdev->mdm_boot);
else
- first_boot = 0;
+ mdev->first_boot = 0;
/* If successful, start a timer to check that the mdm2ap_status
* gpio goes high.
*/
if (!status && gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
- schedule_delayed_work(&mdm2ap_status_check_work,
+ schedule_delayed_work(&mdev->mdm2ap_status_check_work,
msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
break;
case RAM_DUMP_DONE:
@@ -259,24 +419,26 @@
if (status)
mdm_drv->mdm_ram_dump_status = -EIO;
else {
- pr_info("%s: ramdump collection completed\n", __func__);
+ pr_debug("%s: ramdump collection completed\n",
+ __func__);
mdm_drv->mdm_ram_dump_status = 0;
}
- complete(&mdm_ram_dumps);
+ complete(&mdev->mdm_ram_dumps);
break;
case WAIT_FOR_RESTART:
pr_debug("%s: wait for mdm to need images reloaded\n",
__func__);
- ret = wait_for_completion_interruptible(&mdm_needs_reload);
+ ret = wait_for_completion_interruptible(
+ &mdev->mdm_needs_reload);
if (!ret)
put_user(mdm_drv->boot_type,
(unsigned long __user *) arg);
- INIT_COMPLETION(mdm_needs_reload);
+ init_completion(&mdev->mdm_needs_reload);
break;
case GET_DLOAD_STATUS:
pr_debug("getting status of mdm2ap_errfatal_gpio\n");
if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
- !mdm_drv->mdm_ready)
+ !atomic_read(&mdm_drv->mdm_ready))
put_user(1, (unsigned long __user *) arg);
else
put_user(0, (unsigned long __user *) arg);
@@ -284,18 +446,18 @@
case IMAGE_UPGRADE:
pr_debug("%s Image upgrade ioctl recieved\n", __func__);
if (mdm_drv->pdata->image_upgrade_supported &&
- mdm_drv->ops->image_upgrade_cb) {
+ mdm_ops->image_upgrade_cb) {
get_user(status, (unsigned long __user *) arg);
- mdm_drv->ops->image_upgrade_cb(mdm_drv, status);
+ mdm_ops->image_upgrade_cb(mdm_drv, status);
} else
pr_debug("%s Image upgrade not supported\n", __func__);
break;
case SHUTDOWN_CHARM:
if (!mdm_drv->pdata->send_shdn)
break;
- mdm_drv->mdm_ready = 0;
+ atomic_set(&mdm_drv->mdm_ready, 0);
if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
- pr_info("Sending shutdown request to mdm\n");
+ pr_debug("Sending shutdown request to mdm\n");
ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
if (ret)
pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
@@ -307,68 +469,76 @@
ret = -EINVAL;
break;
}
-
return ret;
}
static void mdm_status_fn(struct work_struct *work)
{
+ struct mdm_device *mdev =
+ container_of(work, struct mdm_device, mdm_status_work);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
pr_debug("%s: status:%d\n", __func__, value);
- if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
- mdm_drv->ops->status_cb(mdm_drv, value);
+ if (atomic_read(&mdm_drv->mdm_ready) && mdm_ops->status_cb)
+ mdm_ops->status_cb(mdm_drv, value);
/* Update gpio configuration to "running" config. */
- mdm_update_gpio_configs(GPIO_UPDATE_RUNNING_CONFIG);
+ mdm_update_gpio_configs(mdev, GPIO_UPDATE_RUNNING_CONFIG);
}
-static DECLARE_WORK(mdm_status_work, mdm_status_fn);
-
-static void mdm_disable_irqs(void)
+static void mdm_disable_irqs(struct mdm_device *mdev)
{
- disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
- disable_irq_nosync(mdm_drv->mdm_status_irq);
+ if (!mdev)
+ return;
+ disable_irq_nosync(mdev->mdm_errfatal_irq);
+ disable_irq_nosync(mdev->mdm_status_irq);
+ disable_irq_nosync(mdev->mdm_pblrdy_irq);
}
static irqreturn_t mdm_errfatal(int irq, void *dev_id)
{
- pr_debug("%s: mdm got errfatal interrupt\n", __func__);
- if (mdm_drv->mdm_ready &&
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ if (!mdev)
+ return IRQ_HANDLED;
+
+ pr_debug("%s: mdm id %d sent errfatal interrupt\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_drv = &mdev->mdm_data;
+ if (atomic_read(&mdm_drv->mdm_ready) &&
(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
- pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
- mdm_drv->mdm_ready = 0;
- subsystem_restart_dev(mdm_subsys_dev);
+ pr_debug("%s: Received err fatal from mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_start_ssr(mdev);
}
return IRQ_HANDLED;
}
+/* set the mdm_device as the file's private data */
static int mdm_modem_open(struct inode *inode, struct file *file)
{
+ struct miscdevice *misc = file->private_data;
+ struct mdm_device *mdev = container_of(misc,
+ struct mdm_device, misc_device);
+
+ file->private_data = mdev;
return 0;
}
-static const struct file_operations mdm_modem_fops = {
- .owner = THIS_MODULE,
- .open = mdm_modem_open,
- .unlocked_ioctl = mdm_modem_ioctl,
-};
-
-
-static struct miscdevice mdm_modem_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "mdm",
- .fops = &mdm_modem_fops
-};
-
static int mdm_panic_prep(struct notifier_block *this,
unsigned long event, void *ptr)
{
int i;
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev =
+ container_of(this, struct mdm_device, mdm_panic_blk);
+
+ mdm_drv = &mdev->mdm_data;
pr_debug("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
__func__);
- mdm_disable_irqs();
+ mdm_disable_irqs(mdev);
gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
@@ -380,49 +550,67 @@
if (i <= 0) {
pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
/* Reset the modem so that it will go into download mode. */
- if (mdm_drv && mdm_drv->ops->atomic_reset_mdm_cb)
- mdm_drv->ops->atomic_reset_mdm_cb(mdm_drv);
+ if (mdm_drv && mdm_ops->atomic_reset_mdm_cb)
+ mdm_ops->atomic_reset_mdm_cb(mdm_drv);
}
return NOTIFY_DONE;
}
-static struct notifier_block mdm_panic_blk = {
- .notifier_call = mdm_panic_prep,
-};
-
static irqreturn_t mdm_status_change(int irq, void *dev_id)
{
- int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ int value;
+ if (!mdev)
+ return IRQ_HANDLED;
+
+ mdm_drv = &mdev->mdm_data;
+ value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0))
- pr_info("%s: mdm2ap_status went low\n", __func__);
+ pr_debug("%s: mdm2ap_status went low\n", __func__);
- pr_debug("%s: mdm sent status change interrupt\n", __func__);
- if (value == 0 && mdm_drv->mdm_ready == 1) {
- pr_info("%s: unexpected reset external modem\n", __func__);
+ pr_debug("%s: mdm id %d sent status change interrupt\n",
+ __func__, mdev->mdm_data.device_id);
+ if (value == 0 && atomic_read(&mdm_drv->mdm_ready)) {
+ pr_debug("%s: unexpected reset external modem id %d\n",
+ __func__, mdev->mdm_data.device_id);
mdm_drv->mdm_unexpected_reset_occurred = 1;
- mdm_drv->mdm_ready = 0;
- subsystem_restart_dev(mdm_subsys_dev);
+ mdm_start_ssr(mdev);
} else if (value == 1) {
- cancel_delayed_work(&mdm2ap_status_check_work);
- pr_info("%s: status = 1: mdm is now ready\n", __func__);
- queue_work(mdm_queue, &mdm_status_work);
+ cancel_delayed_work(&mdev->mdm2ap_status_check_work);
+ pr_debug("%s: status = 1: mdm id %d is now ready\n",
+ __func__, mdev->mdm_data.device_id);
+ queue_work(mdev->mdm_queue, &mdev->mdm_status_work);
}
return IRQ_HANDLED;
}
static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id)
{
- pr_info("%s: pbl ready:%d\n", __func__,
- gpio_get_value(mdm_drv->mdm2ap_pblrdy));
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ if (!mdev)
+ return IRQ_HANDLED;
+ mdm_drv = &mdev->mdm_data;
+ pr_debug("%s: mdm id %d: pbl ready:%d\n",
+ __func__, mdev->mdm_data.device_id,
+ gpio_get_value(mdm_drv->mdm2ap_pblrdy));
return IRQ_HANDLED;
}
static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
{
- mdm_drv->mdm_ready = 0;
- cancel_delayed_work(&mdm2ap_status_check_work);
+ struct mdm_device *mdev =
+ container_of(crashed_subsys, struct mdm_device, mdm_subsys);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+ pr_debug("%s: ssr on modem id %d\n", __func__,
+ mdev->mdm_data.device_id);
+
+ mdm_ssr_started(mdev);
+ cancel_delayed_work(&mdev->mdm2ap_status_check_work);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
if (mdm_drv->pdata->ramdump_delay_ms > 0) {
/* Wait for the external modem to complete
@@ -431,9 +619,9 @@
msleep(mdm_drv->pdata->ramdump_delay_ms);
}
if (!mdm_drv->mdm_unexpected_reset_occurred) {
- mdm_drv->ops->reset_mdm_cb(mdm_drv);
+ mdm_ops->reset_mdm_cb(mdm_drv);
/* Update gpio configuration to "booting" config. */
- mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+ mdm_update_gpio_configs(mdev, GPIO_UPDATE_BOOTING_CONFIG);
} else {
mdm_drv->mdm_unexpected_reset_occurred = 0;
}
@@ -442,63 +630,76 @@
static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
{
+ struct mdm_device *mdev =
+ container_of(crashed_subsys, struct mdm_device,
+ mdm_subsys);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+ pr_debug("%s: ssr on modem id %d\n",
+ __func__, mdev->mdm_data.device_id);
+
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
if (mdm_drv->pdata->ps_hold_delay_ms > 0)
msleep(mdm_drv->pdata->ps_hold_delay_ms);
- mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+ mdm_ops->power_on_mdm_cb(mdm_drv);
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
- complete(&mdm_needs_reload);
- if (!wait_for_completion_timeout(&mdm_boot,
+ mdm_ssr_completed(mdev);
+ complete(&mdev->mdm_needs_reload);
+ if (!wait_for_completion_timeout(&mdev->mdm_boot,
msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
mdm_drv->mdm_boot_status = -ETIMEDOUT;
- pr_info("%s: mdm modem restart timed out.\n", __func__);
+ pr_debug("%s: mdm modem restart timed out.\n", __func__);
} else {
- pr_info("%s: mdm modem has been restarted\n", __func__);
+ pr_debug("%s: id %d: mdm modem has been restarted\n",
+ __func__, mdm_drv->device_id);
/* Log the reason for the restart */
if (mdm_drv->pdata->sfr_query)
- queue_work(mdm_sfr_queue, &sfr_reason_work);
+ queue_work(mdev->mdm_sfr_queue, &mdev->sfr_reason_work);
}
- INIT_COMPLETION(mdm_boot);
+ init_completion(&mdev->mdm_boot);
return mdm_drv->mdm_boot_status;
}
static int mdm_subsys_ramdumps(int want_dumps,
const struct subsys_desc *crashed_subsys)
{
+ struct mdm_device *mdev =
+ container_of(crashed_subsys, struct mdm_device,
+ mdm_subsys);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+ pr_debug("%s: ssr on modem id %d\n", __func__,
+ mdev->mdm_data.device_id);
+
mdm_drv->mdm_ram_dump_status = 0;
- cancel_delayed_work(&mdm2ap_status_check_work);
+ cancel_delayed_work(&mdev->mdm2ap_status_check_work);
if (want_dumps) {
mdm_drv->boot_type = CHARM_RAM_DUMPS;
- complete(&mdm_needs_reload);
- if (!wait_for_completion_timeout(&mdm_ram_dumps,
- msecs_to_jiffies(dump_timeout_ms))) {
+ complete(&mdev->mdm_needs_reload);
+ if (!wait_for_completion_timeout(&mdev->mdm_ram_dumps,
+ msecs_to_jiffies(mdev->dump_timeout_ms))) {
mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
- pr_info("%s: mdm modem ramdumps timed out.\n",
+ mdm_ssr_completed(mdev);
+ pr_err("%s: mdm modem ramdumps timed out.\n",
__func__);
} else
- pr_info("%s: mdm modem ramdumps completed.\n",
+ pr_debug("%s: mdm modem ramdumps completed.\n",
__func__);
- INIT_COMPLETION(mdm_ram_dumps);
+ init_completion(&mdev->mdm_ram_dumps);
if (!mdm_drv->pdata->no_powerdown_after_ramdumps) {
- mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+ mdm_ops->power_down_mdm_cb(mdm_drv);
/* Update gpio configuration to "booting" config. */
- mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+ mdm_update_gpio_configs(mdev,
+ GPIO_UPDATE_BOOTING_CONFIG);
}
}
return mdm_drv->mdm_ram_dump_status;
}
-static struct subsys_desc mdm_subsystem = {
- .shutdown = mdm_subsys_shutdown,
- .ramdump = mdm_subsys_ramdumps,
- .powerup = mdm_subsys_powerup,
- .name = EXTERNAL_MODEM,
-};
-
/* Once the gpios are sent to RPM and debugging
* starts, there is no way to stop it without
* rebooting the device.
@@ -512,8 +713,8 @@
}
mdm_debug_mask = val;
- if (mdm_drv->ops->debug_state_changed_cb)
- mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
+ if (mdm_ops->debug_state_changed_cb)
+ mdm_ops->debug_state_changed_cb(mdm_debug_mask);
return 0;
}
@@ -540,11 +741,55 @@
return 0;
}
-static void mdm_modem_initialize_data(struct platform_device *pdev,
- struct mdm_ops *mdm_ops)
+static const struct file_operations mdm_modem_fops = {
+ .owner = THIS_MODULE,
+ .open = mdm_modem_open,
+ .unlocked_ioctl = mdm_modem_ioctl,
+};
+
+static void mdm_modem_initialize_data(struct platform_device *pdev,
+ struct mdm_device *mdev)
{
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
struct resource *pres;
+ mdm_drv->pdata = pdev->dev.platform_data;
+ if (pdev->id < 0)
+ mdm_drv->device_id = 0;
+ else
+ mdm_drv->device_id = pdev->id;
+
+ memset((void *)&mdev->mdm_subsys, 0,
+ sizeof(struct subsys_desc));
+ if (mdev->mdm_data.device_id <= 0)
+ snprintf(mdev->subsys_name, sizeof(mdev->subsys_name),
+ "%s", EXTERNAL_MODEM);
+ else
+ snprintf(mdev->subsys_name, sizeof(mdev->subsys_name),
+ "%s.%d", EXTERNAL_MODEM, mdev->mdm_data.device_id);
+ mdev->mdm_subsys.shutdown = mdm_subsys_shutdown;
+ mdev->mdm_subsys.ramdump = mdm_subsys_ramdumps;
+ mdev->mdm_subsys.powerup = mdm_subsys_powerup;
+ mdev->mdm_subsys.name = mdev->subsys_name;
+
+ memset((void *)&mdev->misc_device, 0,
+ sizeof(struct miscdevice));
+ if (mdev->mdm_data.device_id <= 0)
+ snprintf(mdev->device_name, sizeof(mdev->device_name),
+ "%s", DEVICE_BASE_NAME);
+ else
+ snprintf(mdev->device_name, sizeof(mdev->device_name),
+ "%s%d", DEVICE_BASE_NAME, mdev->mdm_data.device_id);
+ mdev->misc_device.minor = MISC_DYNAMIC_MINOR;
+ mdev->misc_device.name = mdev->device_name;
+ mdev->misc_device.fops = &mdm_modem_fops;
+
+ memset((void *)&mdev->mdm_panic_blk, 0,
+ sizeof(struct notifier_block));
+ mdev->mdm_panic_blk.notifier_call = mdm_panic_prep;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &mdev->mdm_panic_blk);
+
/* MDM2AP_ERRFATAL */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"MDM2AP_ERRFATAL");
@@ -602,26 +847,49 @@
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
- mdm_drv->ops = mdm_ops;
- mdm_drv->pdata = pdev->dev.platform_data;
- dump_timeout_ms = mdm_drv->pdata->ramdump_timeout_ms > 0 ?
+ mdm_drv->dump_timeout_ms = mdm_drv->pdata->ramdump_timeout_ms > 0 ?
mdm_drv->pdata->ramdump_timeout_ms : MDM_RDUMP_TIMEOUT;
+
+ init_completion(&mdev->mdm_needs_reload);
+ init_completion(&mdev->mdm_boot);
+ init_completion(&mdev->mdm_ram_dumps);
+
+ mdev->first_boot = 1;
+ mutex_init(&mdm_drv->peripheral_status_lock);
}
-int mdm_common_create(struct platform_device *pdev,
- struct mdm_ops *p_mdm_cb)
+static void mdm_deconfigure_ipc(struct mdm_device *mdev)
{
- int ret = -1, irq;
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
- mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
- if (mdm_drv == NULL) {
- pr_err("%s: kzalloc fail.\n", __func__);
- goto alloc_err;
+ gpio_free(mdm_drv->ap2mdm_status_gpio);
+ gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
+ gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
+ gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
+ gpio_free(mdm_drv->mdm2ap_status_gpio);
+ gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
+ gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
+
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
+ gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+ if (mdev->mdm_queue) {
+ destroy_workqueue(mdev->mdm_queue);
+ mdev->mdm_queue = NULL;
}
+ if (mdev->mdm_sfr_queue) {
+ destroy_workqueue(mdev->mdm_sfr_queue);
+ mdev->mdm_sfr_queue = NULL;
+ }
+}
- mdm_modem_initialize_data(pdev, p_mdm_cb);
- if (mdm_drv->ops->debug_state_changed_cb)
- mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
+static int mdm_configure_ipc(struct mdm_device *mdev)
+{
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+ int ret = -1, irq;
gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
@@ -648,7 +916,6 @@
mdm_drv->usb_switch_gpio = -1;
}
}
-
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
@@ -658,97 +925,88 @@
gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
- mdm_queue = create_singlethread_workqueue("mdm_queue");
- if (!mdm_queue) {
- pr_err("%s: could not create workqueue. All mdm "
- "functionality will be disabled\n",
- __func__);
+ mdev->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+ if (!mdev->mdm_queue) {
+ pr_err("%s: could not create mdm_queue for mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
ret = -ENOMEM;
goto fatal_err;
}
- mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
- if (!mdm_sfr_queue) {
- pr_err("%s: could not create workqueue mdm_sfr_queue."
- " All mdm functionality will be disabled\n",
- __func__);
+ mdev->mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+ if (!mdev->mdm_sfr_queue) {
+ pr_err("%s: could not create mdm_sfr_queue for mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
ret = -ENOMEM;
- destroy_workqueue(mdm_queue);
goto fatal_err;
}
- atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
- mdm_debugfs_init();
-
/* Register subsystem handlers */
- mdm_subsys_dev = subsys_register(&mdm_subsystem);
- if (IS_ERR(mdm_subsys_dev)) {
- ret = PTR_ERR(mdm_subsys_dev);
+ mdev->mdm_subsys_dev = subsys_register(&mdev->mdm_subsys);
+ if (IS_ERR(mdev->mdm_subsys_dev)) {
+ ret = PTR_ERR(mdev->mdm_subsys_dev);
goto fatal_err;
}
- subsys_default_online(mdm_subsys_dev);
+ subsys_default_online(mdev->mdm_subsys_dev);
/* ERR_FATAL irq. */
- irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
+ irq = gpio_to_irq(mdm_drv->mdm2ap_errfatal_gpio);
if (irq < 0) {
- pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
- "error=%d No IRQ will be generated on errfatal.",
- __func__, irq);
+ pr_err("%s: bad MDM2AP_ERRFATAL IRQ resource, err = %d\n",
+ __func__, irq);
goto errfatal_err;
}
ret = request_irq(irq, mdm_errfatal,
- IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
+ IRQF_TRIGGER_RISING , "mdm errfatal", mdev);
if (ret < 0) {
- pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
- ". No IRQ will be generated on errfatal.",
- __func__, irq, ret);
+ pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed, err=%d\n",
+ __func__, irq, ret);
goto errfatal_err;
}
- mdm_drv->mdm_errfatal_irq = irq;
+ mdev->mdm_errfatal_irq = irq;
errfatal_err:
- /* status irq */
- irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
+ /* status irq */
+ irq = gpio_to_irq(mdm_drv->mdm2ap_status_gpio);
if (irq < 0) {
- pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
- "error=%d No IRQ will be generated on status change.",
- __func__, irq);
+ pr_err("%s: bad MDM2AP_STATUS IRQ resource, err = %d\n",
+ __func__, irq);
goto status_err;
}
ret = request_threaded_irq(irq, NULL, mdm_status_change,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
- "mdm status", mdm_drv);
+ "mdm status", mdev);
if (ret < 0) {
- pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
- ". No IRQ will be generated on status change.",
- __func__, irq, ret);
+ pr_err("%s: MDM2AP_STATUS IRQ#%d request failed, err=%d",
+ __func__, irq, ret);
goto status_err;
}
- mdm_drv->mdm_status_irq = irq;
+ mdev->mdm_status_irq = irq;
status_err:
if (GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy)) {
- irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_pblrdy);
+ irq = gpio_to_irq(mdm_drv->mdm2ap_pblrdy);
if (irq < 0) {
- pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource",
- __func__);
+ pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource\n",
+ __func__);
goto pblrdy_err;
}
ret = request_threaded_irq(irq, NULL, mdm_pblrdy_change,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
- IRQF_SHARED,
- "mdm pbl ready", mdm_drv);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_SHARED,
+ "mdm pbl ready", mdev);
if (ret < 0) {
- pr_err("%s: MDM2AP_PBL IRQ#%d request failed error=%d",
+ pr_err("%s: MDM2AP_PBL IRQ#%d request failed error=%d\n",
__func__, irq, ret);
goto pblrdy_err;
}
+ mdev->mdm_pblrdy_irq = irq;
}
pblrdy_err:
@@ -759,67 +1017,136 @@
if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
- /* Perform early powerup of the external modem in order to
- * allow tabla devices to be found.
- */
- if (mdm_drv->pdata->early_power_on)
- mdm_drv->ops->power_on_mdm_cb(mdm_drv);
-
- pr_info("%s: Registering mdm modem\n", __func__);
- return misc_register(&mdm_modem_misc);
+ return 0;
fatal_err:
- gpio_free(mdm_drv->ap2mdm_status_gpio);
- gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
- gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
- gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
- gpio_free(mdm_drv->mdm2ap_status_gpio);
- gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
- gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
-
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
- gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
-
- kfree(mdm_drv);
- ret = -ENODEV;
-
-alloc_err:
+ mdm_deconfigure_ipc(mdev);
return ret;
}
-int mdm_common_modem_remove(struct platform_device *pdev)
+static int __devinit mdm_modem_probe(struct platform_device *pdev)
+{
+ struct mdm_device *mdev = NULL;
+ int ret = -1;
+
+ mdev = kzalloc(sizeof(struct mdm_device), GFP_KERNEL);
+ if (!mdev) {
+ pr_err("%s: kzalloc fail.\n", __func__);
+ ret = -ENOMEM;
+ goto init_err;
+ }
+
+ platform_set_drvdata(pdev, mdev);
+ mdm_modem_initialize_data(pdev, mdev);
+
+ if (mdm_ops->debug_state_changed_cb)
+ mdm_ops->debug_state_changed_cb(mdm_debug_mask);
+
+ if (mdm_configure_ipc(mdev)) {
+ pr_err("%s: mdm_configure_ipc failed, id = %d\n",
+ __func__, mdev->mdm_data.device_id);
+ goto init_err;
+ }
+
+ pr_debug("%s: Registering mdm id %d\n", __func__,
+ mdev->mdm_data.device_id);
+ ret = misc_register(&mdev->misc_device);
+ if (ret) {
+ pr_err("%s: failed registering mdm id %d, ret = %d\n",
+ __func__, mdev->mdm_data.device_id, ret);
+ mdm_deconfigure_ipc(mdev);
+ goto init_err;
+ } else {
+ pr_err("%s: registered mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+
+ mdm_device_list_add(mdev);
+ INIT_DELAYED_WORK(&mdev->mdm2ap_status_check_work,
+ mdm2ap_status_check);
+ INIT_WORK(&mdev->mdm_status_work, mdm_status_fn);
+ INIT_WORK(&mdev->sfr_reason_work, mdm_restart_reason_fn);
+
+ /* Perform early powerup of the external modem in order to
+ * allow tabla devices to be found.
+ */
+ if (mdev->mdm_data.pdata->early_power_on)
+ mdm_ops->power_on_mdm_cb(&mdev->mdm_data);
+ }
+
+ return ret;
+
+init_err:
+ kfree(mdev);
+ return ret;
+}
+
+static int __devexit mdm_modem_remove(struct platform_device *pdev)
{
int ret;
+ struct mdm_device *mdev = platform_get_drvdata(pdev);
- gpio_free(mdm_drv->ap2mdm_status_gpio);
- gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
- gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
- gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
- gpio_free(mdm_drv->mdm2ap_status_gpio);
- gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
- gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
-
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
- gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
-
- kfree(mdm_drv);
-
- ret = misc_deregister(&mdm_modem_misc);
+ pr_debug("%s: removing device id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_deconfigure_ipc(mdev);
+ ret = misc_deregister(&mdev->misc_device);
+ mdm_device_list_remove(mdev);
+ kfree(mdev);
return ret;
}
-void mdm_common_modem_shutdown(struct platform_device *pdev)
+static void mdm_modem_shutdown(struct platform_device *pdev)
{
- mdm_disable_irqs();
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = platform_get_drvdata(pdev);
- mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+ pr_debug("%s: shutting down device id %d\n",
+ __func__, mdev->mdm_data.device_id);
+
+ mdm_disable_irqs(mdev);
+ mdm_drv = &mdev->mdm_data;
+ mdm_ops->power_down_mdm_cb(mdm_drv);
if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 0);
}
+static struct of_device_id mdm_match_table[] = {
+ {.compatible = "qcom,mdm2_modem,mdm2_modem.1"},
+ {},
+};
+
+static struct platform_driver mdm_modem_driver = {
+ .probe = mdm_modem_probe,
+ .remove = __devexit_p(mdm_modem_remove),
+ .shutdown = mdm_modem_shutdown,
+ .driver = {
+ .name = "mdm2_modem",
+ .owner = THIS_MODULE,
+ .of_match_table = mdm_match_table,
+ },
+};
+
+static int __init mdm_modem_init(void)
+{
+ int ret;
+
+ ret = mdm_get_ops(&mdm_ops);
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&mdm_devices);
+ mdm_debugfs_init();
+ return platform_driver_register(&mdm_modem_driver);
+}
+
+static void __exit mdm_modem_exit(void)
+{
+ platform_driver_unregister(&mdm_modem_driver);
+}
+
+module_init(mdm_modem_init);
+module_exit(mdm_modem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdm modem driver");
+MODULE_VERSION("2.0");
+MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 92fb141..5a91cf9 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -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
@@ -44,25 +44,22 @@
unsigned mdm2ap_pblrdy;
unsigned usb_switch_gpio;
- int mdm_errfatal_irq;
- int mdm_status_irq;
- int mdm_ready;
+ atomic_t mdm_ready;
int mdm_boot_status;
int mdm_ram_dump_status;
enum charm_boot_type boot_type;
int mdm_debug_on;
int mdm_unexpected_reset_occurred;
int disable_status_check;
+ unsigned int dump_timeout_ms;
+ int power_on_count;
+ int peripheral_status;
+ struct mutex peripheral_status_lock;
+ int device_id;
- struct mdm_ops *ops;
struct mdm_platform_data *pdata;
};
-
-int mdm_common_create(struct platform_device *pdev,
- struct mdm_ops *mdm_cb);
-int mdm_common_modem_remove(struct platform_device *pdev);
-void mdm_common_modem_shutdown(struct platform_device *pdev);
-void mdm_common_set_debug_state(int value);
+int mdm_get_ops(struct mdm_ops **mdm_ops);
#endif
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index d7d3081..7a7fb99 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -315,6 +315,8 @@
unsigned long memory_remove_prop_length;
unsigned long memory_size_prop_length;
unsigned int *memory_size_prop;
+ unsigned int *memory_reserve_prop;
+ unsigned long memory_reserve_prop_length;
unsigned int memory_size;
unsigned int memory_start;
int ret;
@@ -326,7 +328,11 @@
"qcom,memblock-remove",
&memory_remove_prop_length);
- if (memory_name_prop || memory_remove_prop) {
+ memory_reserve_prop = of_get_flat_dt_prop(node,
+ "qcom,memblock-reserve",
+ &memory_reserve_prop_length);
+
+ if (memory_name_prop || memory_remove_prop || memory_reserve_prop) {
if (!check_for_compat(node))
goto out;
} else {
@@ -365,7 +371,7 @@
if (memory_remove_prop) {
if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
WARN(1, "Memory remove malformed\n");
- goto out;
+ goto mem_reserve;
}
memory_start = be32_to_cpu(memory_remove_prop[0]);
@@ -380,6 +386,26 @@
memory_start, memory_start+memory_size);
}
+mem_reserve:
+
+ if (memory_reserve_prop) {
+ if (memory_reserve_prop_length != (2*sizeof(unsigned int))) {
+ WARN(1, "Memory reserve malformed\n");
+ goto out;
+ }
+
+ memory_start = be32_to_cpu(memory_reserve_prop[0]);
+ memory_size = be32_to_cpu(memory_reserve_prop[1]);
+
+ ret = memblock_reserve(memory_start, memory_size);
+ if (ret)
+ WARN(1, "Failed to reserve memory %x-%x\n",
+ memory_start, memory_start+memory_size);
+ else
+ pr_info("Node %s memblock_reserve memory %x-%x\n",
+ uname, memory_start, memory_start+memory_size);
+ }
+
out:
return 0;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index eddf017..9b16944 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -59,6 +59,8 @@
return 1;
switch (w) {
+ case 0:
+ WARN(1, "AXI: Divide by 0 attempted\n");
case 1: return bw;
case 2: return (bw >> 1);
case 4: return (bw >> 2);
@@ -342,6 +344,15 @@
return -ENXIO;
}
+ /**
+ * If master supports dual configuration, check if
+ * the configuration needs to be changed based on
+ * incoming requests
+ */
+ if (info->node_info->dual_conf)
+ fabdev->algo->config_master(fabdev, info,
+ req_clk, req_bw);
+
info->link_info.sel_bw = &info->link_info.bw[ctx];
info->link_info.sel_clk = &info->link_info.clk[ctx];
*info->link_info.sel_bw += add_bw;
@@ -417,6 +428,13 @@
req_clk);
bwsum_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth,
bwsum);
+ /* Account for multiple channels if any */
+ if (hop->node_info->num_sports > 1)
+ bwsum_hz = msm_bus_div64(hop->node_info->num_sports,
+ bwsum_hz);
+ MSM_BUS_DBG("AXI: Hop: %d, ports: %d, bwsum_hz: %llu\n",
+ hop->node_info->id, hop->node_info->num_sports,
+ bwsum_hz);
MSM_BUS_DBG("up-clk: curr_hz: %llu, req_hz: %llu, bw_hz %llu\n",
curr_clk, req_clk, bwsum_hz);
ret = fabdev->algo->update_clks(fabdev, hop, index,
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 d531aaa..bc15fe8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -26,6 +26,10 @@
SLAVE_BLOCK_SCMO,
};
+enum bke_sw {
+ BKE_OFF = 0,
+ BKE_ON = 1,
+};
/* Misc module */
@@ -1367,7 +1371,7 @@
(M_BKE_GC_GC_BMSK >> \
M_BKE_GC_GC_SHFT)
-static int bimc_div(uint64_t *a, uint32_t b)
+static int bimc_div(int64_t *a, uint32_t b)
{
if ((*a > 0) && (*a < b))
return 1;
@@ -1508,7 +1512,7 @@
val0 = BKE_HEALTH_VAL(qmode->rl.qhealth[index].limit_commands,
qmode->rl.qhealth[index].areq_prio,
qmode->rl.qhealth[index].prio_level);
- val = (reg_val & (~(BKE_HEALTH_MASK) | (val0 & BKE_HEALTH_MASK)));
+ val = ((reg_val & (~(BKE_HEALTH_MASK))) | (val0 & BKE_HEALTH_MASK));
writel_relaxed(val, addr);
/* Ensure that priority for regulator/limiter modes are
* set before returning
@@ -1563,7 +1567,7 @@
mas_index), M_BKE_HEALTH_2_CONFIG_RMSK, 2, qmode);
set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(binfo->base,
mas_index), M_BKE_HEALTH_1_CONFIG_RMSK, 1, qmode);
- set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(binfo->base,
+ set_qos_prio_rl(M_BKE_HEALTH_0_CONFIG_ADDR(binfo->base,
mas_index), M_BKE_HEALTH_0_CONFIG_RMSK, 0 , qmode);
break;
case BIMC_QOS_MODE_BYPASS:
@@ -1573,10 +1577,11 @@
}
static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index,
- long int th, long int tm, long int tl, uint32_t gp,
+ int32_t th, int32_t tm, int32_t tl, uint32_t gp,
uint32_t gc, bool bke_en)
{
- uint32_t reg_val, val;
+ int32_t reg_val, val;
+ int16_t val2;
/* Disable BKE before writing to registers as per spec */
reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
@@ -1605,15 +1610,15 @@
reg_val = readl_relaxed(M_BKE_THM_ADDR(baddr, mas_index)) &
M_BKE_THM_RMSK;
- val = tm << M_BKE_THM_THRESH_SHFT;
- writel_relaxed(((reg_val & ~(M_BKE_THM_THRESH_BMSK)) | (val &
+ val2 = tm << M_BKE_THM_THRESH_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_THM_THRESH_BMSK)) | (val2 &
M_BKE_THM_THRESH_BMSK)), M_BKE_THM_ADDR(baddr, mas_index));
reg_val = readl_relaxed(M_BKE_THL_ADDR(baddr, mas_index)) &
M_BKE_THL_RMSK;
- val = tl << M_BKE_THL_THRESH_SHFT;
+ val2 = tl << M_BKE_THL_THRESH_SHFT;
writel_relaxed(((reg_val & ~(M_BKE_THL_THRESH_BMSK)) |
- (val & M_BKE_THL_THRESH_BMSK)), M_BKE_THL_ADDR(baddr,
+ (val2 & M_BKE_THL_THRESH_BMSK)), M_BKE_THL_ADDR(baddr,
mas_index));
/* Set BKE enable to the value it was */
@@ -1645,10 +1650,10 @@
/* Only calculate if there's a requested bandwidth and window */
if (qbw->bw && qbw->ws) {
- uint64_t th, tm, tl;
+ int64_t th, tm, tl;
uint32_t gp, gc, data_width;
- uint64_t gp_nominal, gp_required, gp_calc, data, temp;
- uint64_t win = qbw->ws * binfo->qos_freq;
+ int64_t gp_nominal, gp_required, gp_calc, data, temp;
+ int64_t win = qbw->ws * binfo->qos_freq;
temp = win;
/*
* Calculate nominal grant period defined by requested
@@ -1675,13 +1680,13 @@
bimc_div(&gp_required, qbw->bw);
/* User min of two grant periods */
- gp = min_t(uint64_t, gp_nominal, gp_required);
+ gp = min_t(int64_t, gp_nominal, gp_required);
/* Calculate bandwith in grants and ceil. */
temp = qbw->bw * gp;
data = data_width * binfo->qos_freq * 1000;
bimc_div(&temp, data);
- gc = min_t(uint64_t, MAX_GC, temp);
+ gc = min_t(int64_t, MAX_GC, temp);
/* Calculate thresholds */
th = qbw->bw - qbw->thh;
@@ -1811,6 +1816,57 @@
kfree(cd);
}
+static void bke_switch(void __iomem *baddr, uint32_t mas_index, bool req)
+{
+ uint32_t reg_val, val;
+
+ val = req << M_BKE_EN_EN_SHFT;
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
+ M_BKE_EN_RMSK;
+ writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
+ M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
+ wmb();
+}
+
+static void msm_bus_bimc_config_master(
+ struct msm_bus_fabric_registration *fab_pdata,
+ struct msm_bus_inode_info *info,
+ uint64_t req_clk, uint64_t req_bw)
+{
+ int mode, i, ports;
+ struct msm_bus_bimc_info *binfo;
+
+ binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
+ ports = info->node_info->num_mports;
+
+ /**
+ * Here check the details of dual configuration.
+ * Take actions based on different modes.
+ * Check for threshold if limiter mode, etc.
+ */
+ if (req_clk > info->node_info->th)
+ mode = info->node_info->mode_thresh;
+ else
+ mode = info->node_info->mode;
+
+ switch (mode) {
+ case BIMC_QOS_MODE_BYPASS:
+ case BIMC_QOS_MODE_FIXED:
+ for (i = 0; i < ports; i++)
+ bke_switch(binfo->base, info->node_info->qport[i],
+ BKE_OFF);
+ break;
+ case BIMC_QOS_MODE_REGULATOR:
+ case BIMC_QOS_MODE_LIMITER:
+ for (i = 0; i < ports; i++)
+ bke_switch(binfo->base, info->node_info->qport[i],
+ BKE_ON);
+ break;
+ default:
+ break;
+ }
+}
+
static void msm_bus_bimc_update_bw(struct msm_bus_inode_info *hop,
struct msm_bus_inode_info *info,
struct msm_bus_fabric_registration *fab_pdata,
@@ -1910,10 +1966,106 @@
return 0;
}
+static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
+ int mport, struct msm_bus_bimc_qos_bw *qbw)
+{
+ int32_t bw_MBps, thh = 0, thm, thl, gc;
+ int16_t gp;
+ u64 temp;
+
+ if (binfo->qos_freq == 0) {
+ MSM_BUS_DBG("Zero QoS Frequency\n");
+ return;
+ }
+
+ if (!(qbw->bw && qbw->ws)) {
+ MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
+ return;
+ }
+
+ /* Convert bandwidth to MBPS */
+ temp = qbw->bw;
+ bimc_div(&temp, 1000000);
+ bw_MBps = temp;
+
+ /* Grant period in clock cycles
+ * Grant period from bandwidth structure
+ * is in micro seconds, QoS freq is in KHz.
+ * Divide by 1000 to get clock cycles */
+ gp = (binfo->qos_freq * qbw->gp) / 1000;
+
+ /* Grant count = BW in MBps * Grant period
+ * in micro seconds */
+ gc = bw_MBps * qbw->gp;
+
+ /* Medium threshold = -((Medium Threshold percentage *
+ * Grant count) / 100) */
+ thm = -((qbw->thmp * gc) / 100);
+ qbw->thm = thm;
+
+ /* Low threshold = -(Grant count) */
+ thl = -gc;
+ qbw->thl = thl;
+
+ set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp,
+ gc, 1);
+}
+
+static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo,
+ struct msm_bus_inode_info *info,
+ struct msm_bus_bimc_qos_mode *qmode, int mode)
+{
+ int i;
+
+ switch (mode) {
+ case BIMC_QOS_MODE_FIXED:
+ qmode->fixed.prio_level = info->node_info->prio_lvl;
+ qmode->fixed.areq_prio_rd = info->node_info->prio_rd;
+ qmode->fixed.areq_prio_wr = info->node_info->prio_wr;
+ break;
+ case BIMC_QOS_MODE_LIMITER:
+ qmode->rl.qhealth[0].limit_commands = 1;
+ qmode->rl.qhealth[1].limit_commands = 0;
+ qmode->rl.qhealth[2].limit_commands = 0;
+ qmode->rl.qhealth[3].limit_commands = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("No QoS Ports to init\n");
+ return;
+ }
+
+ for (i = 0; i < info->node_info->num_mports; i++) {
+ /* If not in bypass mode, update priority */
+ if (mode != BIMC_QOS_MODE_BYPASS) {
+ msm_bus_bimc_set_qos_prio(binfo, info->node_info->
+ qport[i], mode, qmode);
+
+ /* If not in fixed mode, update bandwidth */
+ if (mode != BIMC_QOS_MODE_FIXED) {
+ struct msm_bus_bimc_qos_bw qbw;
+ qbw.ws = info->node_info->ws;
+ qbw.bw = info->node_info->bimc_bw;
+ qbw.gp = info->node_info->bimc_gp;
+ qbw.thmp = info->node_info->bimc_thmp;
+ bimc_set_static_qos_bw(binfo,
+ info->node_info->qport[i], &qbw);
+ }
+ }
+
+ /* set mode */
+ msm_bus_bimc_set_qos_mode(binfo, info->node_info->qport[i],
+ mode);
+ }
+}
+
+
static int msm_bus_bimc_mas_init(struct msm_bus_bimc_info *binfo,
struct msm_bus_inode_info *info)
{
- int i;
struct msm_bus_bimc_qos_mode *qmode;
qmode = kzalloc(sizeof(struct msm_bus_bimc_qos_mode),
GFP_KERNEL);
@@ -1923,42 +2075,17 @@
return -ENOMEM;
}
- switch (info->node_info->mode) {
- case BIMC_QOS_MODE_FIXED:
- qmode->fixed.prio_level = info->node_info->prio_lvl;
- qmode->fixed.areq_prio_rd = info->node_info->prio_rd;
- qmode->fixed.areq_prio_wr = info->node_info->prio_wr;
- break;
- default:
- break;
- }
-
info->hw_data = (void *)qmode;
- if (!info->node_info->qport) {
- MSM_BUS_DBG("No QoS Ports to init\n");
- return 0;
- }
- for (i = 0; i < info->node_info->num_mports; i++) {
- /* If not in bypass mode, update priority */
- if (info->node_info->mode != BIMC_QOS_MODE_BYPASS) {
- msm_bus_bimc_set_qos_prio(binfo, info->node_info->
- qport[i], info->node_info->mode, qmode);
+ /**
+ * If the master supports dual configuration,
+ * configure registers for both modes
+ */
+ if (info->node_info->dual_conf)
+ bimc_init_mas_reg(binfo, info, qmode,
+ info->node_info->mode_thresh);
- /* If not in fixed mode, update bandwidth */
- if (info->node_info->mode != BIMC_QOS_MODE_FIXED) {
- struct msm_bus_bimc_qos_bw qbw;
- qbw.ws = info->node_info->ws;
- msm_bus_bimc_set_qos_bw(binfo,
- info->node_info->qport[i], &qbw);
- }
- }
-
- /* set mode */
- msm_bus_bimc_set_qos_mode(binfo, info->node_info->qport[i],
- info->node_info->mode);
- }
-
+ bimc_init_mas_reg(binfo, info, qmode, info->node_info->mode);
return 0;
}
@@ -1998,6 +2125,7 @@
hw_algo->commit = msm_bus_bimc_commit;
hw_algo->port_halt = msm_bus_bimc_port_halt;
hw_algo->port_unhalt = msm_bus_bimc_port_unhalt;
+ hw_algo->config_master = msm_bus_bimc_config_master;
/* BIMC slaves are shared. Slave registers are set through RPM */
if (!pdata->ahb)
pdata->rpm_enabled = 1;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.h b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.h
index 6df0bea..12c8325 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.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
@@ -93,9 +93,11 @@
struct msm_bus_bimc_qos_bw {
uint64_t bw; /* bw is in Bytes/sec */
uint32_t ws; /* Window size in nano seconds*/
- uint64_t thh; /* Threshold high, bytes per second */
- uint64_t thm; /* Threshold medium, bytes per second */
- uint64_t thl; /* Threshold low, bytes per second */
+ int64_t thh; /* Threshold high, bytes per second */
+ int64_t thm; /* Threshold medium, bytes per second */
+ int64_t thl; /* Threshold low, bytes per second */
+ u32 gp; /* Grant Period in micro seconds */
+ u32 thmp; /* Threshold medium in percentage */
};
struct msm_bus_bimc_clk_gate {
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 98419a4..87719e3 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -81,6 +81,12 @@
unsigned int prio_wr;
unsigned int prio1;
unsigned int prio0;
+ u64 th;
+ unsigned int mode_thresh;
+ bool dual_conf;
+ u64 bimc_bw;
+ u32 bimc_gp;
+ u32 bimc_thmp;
const char *name;
};
@@ -147,6 +153,9 @@
*fab_pdata, void *hw_data, void **cdata);
int (*port_unhalt)(uint32_t haltid, uint8_t mport);
int (*port_halt)(uint32_t haltid, uint8_t mport);
+ void (*config_master)(struct msm_bus_fabric_registration *fab_pdata,
+ struct msm_bus_inode_info *info,
+ uint64_t req_clk, uint64_t req_bw);
};
struct msm_bus_fabric_device {
@@ -179,6 +188,9 @@
void (*update_bw)(struct msm_bus_fabric_device *fabdev, struct
msm_bus_inode_info * hop, struct msm_bus_inode_info *info,
int64_t add_bw, int *master_tiers, int ctx);
+ void (*config_master)(struct msm_bus_fabric_device *fabdev,
+ struct msm_bus_inode_info *info, uint64_t req_clk,
+ uint64_t req_bw);
};
struct msm_bus_board_algorithm {
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 62da5ac..ddf747e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -509,6 +509,46 @@
return status;
}
+static void msm_bus_fabric_config_master(
+ struct msm_bus_fabric_device *fabdev,
+ struct msm_bus_inode_info *info, uint64_t req_clk, uint64_t req_bw)
+{
+ struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+ long rounded_rate;
+
+ if (fabdev->hw_algo.config_master == NULL)
+ return;
+
+ /* Enable clocks before accessing QoS registers */
+ 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);
+
+ fabdev->hw_algo.config_master(fabric->pdata, info, req_clk, req_bw);
+
+ /* Disable clocks after accessing QoS registers */
+ 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",
+ info->node_info->priv_id);
+ clk_disable_unprepare(info->iface_clk.clk);
+ }
+}
+
/**
* msm_bus_fabric_hw_commit() - Commit the arbitration data to Hardware.
* @fabric: Fabric for which the data should be committed
@@ -664,6 +704,7 @@
.find_node = msm_bus_fabric_find_node,
.find_gw_node = msm_bus_fabric_find_gw_node,
.get_gw_list = msm_bus_fabric_get_gw_list,
+ .config_master = msm_bus_fabric_config_master,
};
static int msm_bus_fabric_hw_init(struct msm_bus_fabric_registration *pdata,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index 3ae37e4..d33c340 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.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
@@ -619,6 +619,7 @@
hw_algo->commit = msm_bus_noc_commit;
hw_algo->port_halt = msm_bus_noc_port_halt;
hw_algo->port_unhalt = msm_bus_noc_port_unhalt;
+ hw_algo->config_master = NULL;
return 0;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
index 4e25637..06894c6 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -22,7 +22,7 @@
#include <mach/msm_bus_board.h>
#include "msm_bus_core.h"
-#define KBTOMB(a) (a * 1000ULL)
+#define KBTOB(a) (a * 1000ULL)
static const char * const hw_sel_name[] = {"RPM", "NoC", "BIMC", NULL};
static const char * const mode_sel_name[] = {"Fixed", "Limiter", "Bypass",
"Regulator", NULL};
@@ -129,9 +129,9 @@
usecase[i].vectors[j].dst =
be32_to_cpu(vec_arr[index + 1]);
usecase[i].vectors[j].ab = (uint64_t)
- KBTOMB(be32_to_cpu(vec_arr[index + 2]));
+ KBTOB(be32_to_cpu(vec_arr[index + 2]));
usecase[i].vectors[j].ib = (uint64_t)
- KBTOMB(be32_to_cpu(vec_arr[index + 3]));
+ KBTOB(be32_to_cpu(vec_arr[index + 3]));
}
}
@@ -278,6 +278,7 @@
struct msm_bus_node_info *info;
struct device_node *child_node = NULL;
int i = 0, ret;
+ u32 temp;
for_each_child_of_node(of_node, child_node) {
i++;
@@ -352,6 +353,20 @@
of_property_read_u32(child_node, "qcom,buswidth",
&info[i].buswidth);
of_property_read_u32(child_node, "qcom,ws", &info[i].ws);
+ ret = of_property_read_u32(child_node, "qcom,thresh",
+ &temp);
+ if (!ret)
+ info[i].th = (uint64_t)KBTOB(temp);
+
+ ret = of_property_read_u32(child_node, "qcom,bimc,bw",
+ &temp);
+ if (!ret)
+ info[i].bimc_bw = (uint64_t)KBTOB(temp);
+
+ of_property_read_u32(child_node, "qcom,bimc,gp",
+ &info[i].bimc_gp);
+ of_property_read_u32(child_node, "qcom,bimc,thmp",
+ &info[i].bimc_thmp);
ret = of_property_read_string(child_node, "qcom,mode",
&sel_str);
if (ret)
@@ -366,6 +381,25 @@
info[i].mode = ret;
}
+ info[i].dual_conf =
+ of_property_read_bool(child_node, "qcom,dual-conf");
+
+ ret = of_property_read_string(child_node, "qcom,mode-thresh",
+ &sel_str);
+ if (ret)
+ info[i].mode_thresh = 0;
+ else {
+ ret = get_num(mode_sel_name, sel_str);
+ if (ret < 0) {
+ pr_err("Unknown mode :%s\n", sel_str);
+ goto err;
+ }
+
+ info[i].mode_thresh = ret;
+ MSM_BUS_DBG("AXI: THreshold mode set: %d\n",
+ info[i].mode_thresh);
+ }
+
ret = of_property_read_string(child_node, "qcom,perm-mode",
&sel_str);
if (ret)
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
index 69efd13..5897e1f 100644
--- a/arch/arm/mach-msm/msm_ipc_router_security.c
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -22,6 +22,7 @@
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/msm_ipc.h>
+#include <linux/rwsem.h>
#include <asm/uaccess.h>
@@ -31,6 +32,11 @@
#define IRSC_COMPLETION_TIMEOUT_MS 30000
#define SEC_RULES_HASH_SZ 32
+
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
struct security_rule {
struct list_head list;
uint32_t service_id;
@@ -40,7 +46,7 @@
gid_t *group_id;
};
-static DEFINE_MUTEX(security_rules_lock);
+static DECLARE_RWSEM(security_rules_lock_lha4);
static struct list_head security_rules[SEC_RULES_HASH_SZ];
static DECLARE_COMPLETION(irsc_completion);
@@ -98,7 +104,7 @@
struct config_sec_rules_args sec_rules_arg;
struct security_rule *rule, *temp_rule;
int key;
- int group_info_sz;
+ size_t group_info_sz;
int ret;
if (current_euid())
@@ -112,12 +118,12 @@
if (sec_rules_arg.num_group_info <= 0)
return -EINVAL;
- group_info_sz = sec_rules_arg.num_group_info * sizeof(gid_t);
- if ((group_info_sz / sizeof(gid_t)) != sec_rules_arg.num_group_info) {
+ if (sec_rules_arg.num_group_info > (SIZE_MAX / sizeof(gid_t))) {
pr_err("%s: Integer Overflow %d * %d\n", __func__,
sizeof(gid_t), sec_rules_arg.num_group_info);
return -EINVAL;
}
+ group_info_sz = sec_rules_arg.num_group_info * sizeof(gid_t);
rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
if (!rule) {
@@ -146,7 +152,7 @@
}
key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
- mutex_lock(&security_rules_lock);
+ down_write(&security_rules_lock_lha4);
if (rule->service_id == ALL_SERVICE) {
temp_rule = list_first_entry(&security_rules[key],
struct security_rule, list);
@@ -155,7 +161,7 @@
kfree(temp_rule);
}
list_add_tail(&rule->list, &security_rules[key]);
- mutex_unlock(&security_rules_lock);
+ up_write(&security_rules_lock_lha4);
if (rule->service_id == ALL_SERVICE)
msm_ipc_sync_default_sec_rule((void *)rule);
@@ -198,10 +204,10 @@
rule->instance_id = ALL_INSTANCE;
rule->num_group_info = 1;
*(rule->group_id) = AID_NET_RAW;
- mutex_lock(&security_rules_lock);
+ down_write(&security_rules_lock_lha4);
key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
list_add_tail(&rule->list, &security_rules[key]);
- mutex_unlock(&security_rules_lock);
+ up_write(&security_rules_lock_lha4);
return 0;
}
@@ -222,12 +228,12 @@
struct security_rule *rule;
key = (service_id & (SEC_RULES_HASH_SZ - 1));
- mutex_lock(&security_rules_lock);
+ down_read(&security_rules_lock_lha4);
/* Return the rule for a specific <service:instance>, if found. */
list_for_each_entry(rule, &security_rules[key], list) {
if ((rule->service_id == service_id) &&
(rule->instance_id == instance_id)) {
- mutex_unlock(&security_rules_lock);
+ up_read(&security_rules_lock_lha4);
return (void *)rule;
}
}
@@ -236,7 +242,7 @@
list_for_each_entry(rule, &security_rules[key], list) {
if ((rule->service_id == service_id) &&
(rule->instance_id == ALL_INSTANCE)) {
- mutex_unlock(&security_rules_lock);
+ up_read(&security_rules_lock_lha4);
return (void *)rule;
}
}
@@ -246,10 +252,11 @@
list_for_each_entry(rule, &security_rules[key], list) {
if ((rule->service_id == ALL_SERVICE) &&
(rule->instance_id == ALL_INSTANCE)) {
- mutex_unlock(&security_rules_lock);
+ up_read(&security_rules_lock_lha4);
return (void *)rule;
}
}
+ up_read(&security_rules_lock_lha4);
return NULL;
}
EXPORT_SYMBOL(msm_ipc_get_security_rule);
diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c
index e598ed0..94cbc4b 100644
--- a/arch/arm/mach-msm/nohlt.c
+++ b/arch/arm/mach-msm/nohlt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009, 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
@@ -28,11 +28,18 @@
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n");
+static int get_nohalt(void *data, u64 *val)
+{
+ *val = (unsigned int)get_hlt();
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, get_nohalt, set_nohalt, "%llu\n");
static int __init init_hlt_debug(void)
{
- debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops);
+ debugfs_create_file("nohlt", 0600, NULL, NULL, &nohalt_ops);
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 21c4e1e..a3fd6b2 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1060,13 +1060,6 @@
goto invalid_op_error;
}
- region = create_region();
-
- if (!region) {
- pr_err("ocmem: Unable to create region\n");
- goto invalid_op_error;
- }
-
retry = false;
pr_debug("ocmem: do_allocate: %s request %p size %lx\n",
@@ -1081,6 +1074,14 @@
overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
if (overlap_r == NULL) {
+
+ region = create_region();
+
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto invalid_op_error;
+ }
+
/* no conflicting regions, schedule this region */
rc = zone->z_ops->allocate(zone, sz, &alloc_addr);
@@ -1176,7 +1177,6 @@
trigger_eviction:
pr_debug("Trigger eviction of region %p\n", overlap_r);
- destroy_region(region);
return OP_EVICT;
err_not_supported:
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index c2ba6c1..c09b759 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -46,6 +46,7 @@
#define PCIE20_PARF_PHY_REFCLK 0x4C
#define PCIE20_PARF_CONFIG_BITS 0x50
+#define PCIE20_ELBI_VERSION 0x00
#define PCIE20_ELBI_SYS_CTRL 0x04
#define PCIE20_CAP 0x70
@@ -55,6 +56,8 @@
#define PCIE20_BUSNUMBERS 0x18
#define PCIE20_MEMORY_BASE_LIMIT 0x20
+#define PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL0 0x818
+#define PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL1 0x81c
#define PCIE20_PLR_IATU_VIEWPORT 0x900
#define PCIE20_PLR_IATU_CTRL1 0x904
#define PCIE20_PLR_IATU_CTRL2 0x908
@@ -478,6 +481,27 @@
msm_pcie_dev.axi_conf = NULL;
}
+static void msm_pcie_adjust_tlp_size(struct msm_pcie_dev_t *dev)
+{
+ /*
+ * Apply this fix only for device such as APQ8064 version 1.
+ * Set the Max TLP size to 2K, instead of using default of 4K
+ * to avoid a RAM problem in PCIE20 core of that version.
+ */
+ if (readl_relaxed(dev->elbi + PCIE20_ELBI_VERSION) == 0x01002107) {
+
+ /*
+ * CFG_REMOTE_RD_REQ_BRIDGE_SIZE:
+ * 5=4KB/4=2KB/3=1KB/2=512B/1=256B/0=128B
+ */
+ writel_relaxed(4, dev->pcie20 +
+ PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL0);
+
+ writel_relaxed(1, dev->pcie20 +
+ PCIE20_PLR_AXI_MSTR_RESP_COMP_CTRL1);
+ }
+};
+
static int __init msm_pcie_setup(int nr, struct pci_sys_data *sys)
{
int rc;
@@ -555,6 +579,12 @@
gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
!dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+ /*
+ * adjust tlp size before link comes up
+ * so there will be no transactions.
+ */
+ msm_pcie_adjust_tlp_size(dev);
+
/* enable link training */
msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 5bf88a2..70420db 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -30,6 +30,8 @@
"5 Perf: Add DT support for L1 and L2 PMU\n"
"6 Perf: Add cortex A5 device tree support\n"
"7 Perf: Add L1 counters to tracepoints\n"
+ "8 Perf: Add cortex A7 perf support\n"
+ "9 ARM: dts: msm: add perf-events support for msm8226\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_trace_counters.h b/arch/arm/mach-msm/perf_trace_counters.h
index ce7e336..8f77bad 100644
--- a/arch/arm/mach-msm/perf_trace_counters.h
+++ b/arch/arm/mach-msm/perf_trace_counters.h
@@ -121,7 +121,6 @@
#endif
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_PATH ../../arch/arm/mach-msm
#define TRACE_INCLUDE_FILE perf_trace_counters
#include <trace/define_trace.h>
-
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 19b5671..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 = {
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 5ef6638..8cf6011 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -79,6 +79,8 @@
#define EXTERNAL_BHS_STATUS BIT(4)
#define BHS_TIMEOUT_US 50
+#define STOP_ACK_TIMEOUT_MS 1000
+
struct mba_data {
void __iomem *rmb_base;
void __iomem *io_clamp_reg;
@@ -94,10 +96,12 @@
bool crash_shutdown;
bool ignore_errors;
int err_fatal_irq;
+ unsigned int stop_ack_irq;
int force_stop_gpio;
+ struct completion stop_ack;
};
-static int pbl_mba_boot_timeout_ms = 100;
+static int pbl_mba_boot_timeout_ms = 1000;
module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
static int modem_auth_timeout_ms = 10000;
@@ -217,28 +221,13 @@
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
- /*
- * If the shutdown function is called before the reset function, clocks
- * and power will not be enabled yet. Enable them here so that register
- * writes performed during the shutdown succeed.
- */
- if (drv->is_booted == false) {
- pil_mss_power_up(drv);
- pil_mss_enable_clks(drv);
- }
- pil_q6v5_shutdown(pil);
-
- pil_mss_disable_clks(drv);
-
writel_relaxed(1, drv->restart_reg);
- /*
- * access to the cx_rail_bhs is restricted until after the gcc_mss
- * reset is asserted once the PBL starts executing.
- */
- pil_mss_power_down(drv);
-
- drv->is_booted = false;
+ if (drv->is_booted) {
+ pil_mss_disable_clks(drv);
+ pil_mss_power_down(drv);
+ drv->is_booted = false;
+ }
return 0;
}
@@ -499,16 +488,36 @@
return IRQ_HANDLED;
pr_err("Fatal error on the modem.\n");
+ subsys_set_crash_status(drv->subsys, true);
restart_modem(drv);
return IRQ_HANDLED;
}
+static irqreturn_t modem_stop_ack_intr_handler(int irq, void *dev_id)
+{
+ struct mba_data *drv = dev_id;
+ pr_info("Received stop ack interrupt from modem\n");
+ complete(&drv->stop_ack);
+ return IRQ_HANDLED;
+}
+
static int modem_shutdown(const struct subsys_desc *subsys)
{
struct mba_data *drv = subsys_to_drv(subsys);
+ unsigned long ret;
if (subsys->is_not_loadable)
return 0;
+
+ if (!subsys_get_crash_status(drv->subsys)) {
+ gpio_set_value(drv->force_stop_gpio, 1);
+ ret = wait_for_completion_timeout(&drv->stop_ack,
+ msecs_to_jiffies(STOP_ACK_TIMEOUT_MS));
+ if (!ret)
+ pr_warn("Timed out on stop ack from modem.\n");
+ gpio_set_value(drv->force_stop_gpio, 0);
+ }
+
pil_shutdown(&drv->desc);
pil_shutdown(&drv->q6->desc);
return 0;
@@ -526,6 +535,7 @@
* run concurrently with either the watchdog bite error handler or the
* SMSM callback, making it safe to unset the flag below.
*/
+ init_completion(&drv->stop_ack);
drv->ignore_errors = false;
ret = pil_boot(&drv->q6->desc);
if (ret)
@@ -540,7 +550,10 @@
{
struct mba_data *drv = subsys_to_drv(subsys);
drv->crash_shutdown = true;
- gpio_set_value(drv->force_stop_gpio, 1);
+ if (!subsys_get_crash_status(drv->subsys)) {
+ gpio_set_value(drv->force_stop_gpio, 1);
+ mdelay(STOP_ACK_TIMEOUT_MS);
+ }
}
static struct ramdump_segment smem_segments[] = {
@@ -597,6 +610,7 @@
if (drv->ignore_errors)
return IRQ_HANDLED;
pr_err("Watchdog bite received from modem software!\n");
+ subsys_set_crash_status(drv->subsys, true);
restart_modem(drv);
return IRQ_HANDLED;
}
@@ -609,6 +623,7 @@
if (desc->is_not_loadable)
return 0;
+ init_completion(&drv->stop_ack);
ret = pil_boot(&drv->q6->desc);
if (ret)
return ret;
@@ -703,6 +718,14 @@
goto err_irq;
}
+ ret = devm_request_irq(&pdev->dev, drv->stop_ack_irq,
+ modem_stop_ack_intr_handler,
+ IRQF_TRIGGER_RISING, "pil-mss", drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to register SMP2P stop ack handler!\n");
+ goto err_irq;
+ }
+
drv->adsp_state_notifier = subsys_notif_register_notifier("adsp",
&adsp_state_notifier_block);
if (IS_ERR(drv->adsp_state_notifier)) {
@@ -837,7 +860,7 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
- int ret, err_fatal_gpio, is_not_loadable;
+ int ret, err_fatal_gpio, is_not_loadable, stop_ack_gpio;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
@@ -864,6 +887,16 @@
if (drv->err_fatal_irq < 0)
return drv->err_fatal_irq;
+ stop_ack_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-stop-ack", 0);
+ if (stop_ack_gpio < 0)
+ return stop_ack_gpio;
+
+ ret = gpio_to_irq(stop_ack_gpio);
+ if (ret < 0)
+ return ret;
+ drv->stop_ack_irq = ret;
+
/* Get the GPIO pin for writing the outbound bits: add more as needed */
drv->force_stop_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,gpio-force-stop", 0);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 4a54dd4..545723c 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/cpu.h>
+#include <linux/clk.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
@@ -58,6 +59,7 @@
#include "timer.h"
#include "pm-boot.h"
#include <mach/event_timer.h>
+#include <linux/cpu_pm.h>
#define SCM_L2_RETENTION (0x2)
#define SCM_CMD_TERMINATE_PC (0x2)
@@ -131,6 +133,7 @@
static bool msm_no_ramp_down_pc;
static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
static bool msm_pm_pc_reset_timer;
+static struct clk *pnoc_clk;
static int msm_pm_get_pc_mode(struct device_node *node,
const char *key, uint32_t *pc_mode_val)
@@ -482,6 +485,9 @@
pr_info("CPU%u: %s: notify_rpm %d\n",
cpu, __func__, (int) notify_rpm);
+ if (from_idle == true)
+ cpu_pm_enter();
+
ret = msm_spm_set_low_power_mode(
MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
WARN_ON(ret);
@@ -514,6 +520,10 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
WARN_ON(ret);
+
+ if (from_idle == true)
+ cpu_pm_exit();
+
return collapsed;
}
@@ -884,7 +894,11 @@
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
collapsed = msm_pm_power_collapse_standalone(true);
- exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ if (collapsed)
+ exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ else
+ exit_stat
+ = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
@@ -894,7 +908,11 @@
collapsed = msm_pm_power_collapse(true);
timer_halted = true;
- exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ if (collapsed)
+ exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ else
+ exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+
msm_pm_timer_exit_idle(timer_halted);
break;
@@ -930,13 +948,13 @@
int msm_pm_wait_cpu_shutdown(unsigned int cpu)
{
- int timeout = 10;
+ int timeout = 0;
if (!msm_pm_slp_sts)
return 0;
if (!msm_pm_slp_sts[cpu].base_addr)
return 0;
- while (timeout--) {
+ while (1) {
/*
* Check for the SPM of the core being hotplugged to set
* its sleep state.The SPM sleep state indicates that the
@@ -947,10 +965,10 @@
if (acc_sts & msm_pm_slp_sts[cpu].mask)
return 0;
udelay(100);
+ WARN(++timeout == 10, "CPU%u didn't collape within 1ms\n",
+ cpu);
}
- pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
- __func__, cpu);
return -EBUSY;
}
@@ -1048,6 +1066,7 @@
int ret = -ENODEV;
uint32_t power;
uint32_t msm_pm_max_sleep_time = 0;
+ int collapsed = 0;
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: power collapse\n", __func__);
@@ -1071,7 +1090,7 @@
msm_pm_max_sleep_time,
rs_limits, false, true);
if (!ret) {
- int collapsed = msm_pm_power_collapse(false);
+ collapsed = msm_pm_power_collapse(false);
if (pm_sleep_ops.exit_sleep) {
pm_sleep_ops.exit_sleep(rs_limits,
false, true, collapsed);
@@ -1082,7 +1101,10 @@
__func__);
}
time = msm_pm_timer_exit_suspend(time, period);
- msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+ if (collapsed)
+ msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+ else
+ msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND, time);
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: standalone power collapse\n", __func__);
@@ -1110,9 +1132,24 @@
pm_sleep_ops = *ops;
}
+int msm_suspend_prepare(void)
+{
+ if (pnoc_clk != NULL)
+ clk_disable_unprepare(pnoc_clk);
+ return 0;
+}
+
+void msm_suspend_wake(void)
+{
+ if (pnoc_clk != NULL)
+ clk_prepare_enable(pnoc_clk);
+}
+
static const struct platform_suspend_ops msm_pm_ops = {
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
+ .prepare_late = msm_suspend_prepare,
+ .wake = msm_suspend_wake,
};
static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
@@ -1595,6 +1632,18 @@
return rc;
}
+ pnoc_clk = clk_get_sys("pm_8x60", "bus_clk");
+
+ if (IS_ERR(pnoc_clk))
+ pnoc_clk = NULL;
+ else {
+ clk_set_rate(pnoc_clk, 19200000);
+ rc = clk_prepare_enable(pnoc_clk);
+
+ if (rc)
+ pr_err("%s: PNOC clock enable failed\n", __func__);
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 6e60db1..8d9ad29 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -118,7 +118,7 @@
},
{
.name = "LSM",
- .idx = 9,
+ .idx = 10,
.id = APR_SVC_LSM,
.client_id = APR_CLIENT_AUDIO,
},
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index a177593..4649390 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -73,7 +73,6 @@
#endif
#define MODULE_NAME "msm_smd"
-#define SMEM_VERSION 0x000B
#define SMD_VERSION 0x00020000
#define SMSM_SNAPSHOT_CNT 64
#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
@@ -3802,6 +3801,9 @@
{
int ret;
+ if (!smem_initialized_check())
+ return -ENODEV;
+
SMD_INFO("smd probe\n");
INIT_WORK(&probe_work, smd_channel_probe_worker);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 2204609..bbb6ce0 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -35,6 +35,10 @@
#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
(((type)~0 - (a)) < (b) ? true : false)
+#define MODEM_SBL_VERSION_INDEX 7
+#define SMEM_VERSION_INFO_SIZE (32 * 4)
+#define SMEM_VERSION 0x000B
+
enum {
MSM_SMEM_DEBUG = 1U << 0,
MSM_SMEM_INFO = 1U << 1,
@@ -57,6 +61,7 @@
static void *smem_ramdump_dev;
static DEFINE_MUTEX(spinlock_init_lock);
+static DEFINE_SPINLOCK(smem_init_check_lock);
struct restart_notifier_block {
unsigned processor;
@@ -187,12 +192,48 @@
}
EXPORT_SYMBOL(smem_alloc);
-void *smem_find(unsigned id, unsigned size_in)
+static void *__smem_get_entry(unsigned id, unsigned *size, bool skip_init_check)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ int use_spinlocks = spinlocks_initialized;
+ void *ret = 0;
+ unsigned long flags = 0;
+
+ if (!skip_init_check && !smem_initialized_check())
+ return ret;
+
+ if (id >= SMEM_NUM_ITEMS)
+ return ret;
+
+ if (use_spinlocks)
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ /* toc is in device memory and cannot be speculatively accessed */
+ if (toc[id].allocated) {
+ phys_addr_t phys_base;
+
+ *size = toc[id].size;
+ barrier();
+
+ phys_base = toc[id].reserved & BASE_ADDR_MASK;
+ if (!phys_base)
+ phys_base = (phys_addr_t)msm_shared_ram_phys;
+ ret = smem_phys_to_virt(phys_base, toc[id].offset);
+ } else {
+ *size = 0;
+ }
+ if (use_spinlocks)
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+ return ret;
+}
+
+static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
{
unsigned size;
void *ptr;
- ptr = smem_get_entry(id, &size);
+ ptr = __smem_get_entry(id, &size, skip_init_check);
if (!ptr)
return 0;
@@ -205,6 +246,11 @@
return ptr;
}
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+ return __smem_find(id, size_in, false);
+}
EXPORT_SYMBOL(smem_find);
/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
@@ -218,10 +264,8 @@
void *ret = NULL;
int rc;
- if (!shared->heap_info.initialized) {
- pr_err("%s: smem heap info not initialized\n", __func__);
+ if (!smem_initialized_check())
return NULL;
- }
if (id >= SMEM_NUM_ITEMS)
return NULL;
@@ -268,35 +312,7 @@
void *smem_get_entry(unsigned id, unsigned *size)
{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- int use_spinlocks = spinlocks_initialized;
- void *ret = 0;
- unsigned long flags = 0;
-
- if (id >= SMEM_NUM_ITEMS)
- return ret;
-
- if (use_spinlocks)
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- /* toc is in device memory and cannot be speculatively accessed */
- if (toc[id].allocated) {
- phys_addr_t phys_base;
-
- *size = toc[id].size;
- barrier();
-
- phys_base = toc[id].reserved & BASE_ADDR_MASK;
- if (!phys_base)
- phys_base = (phys_addr_t)msm_shared_ram_phys;
- ret = smem_phys_to_virt(phys_base, toc[id].offset);
- } else {
- *size = 0;
- }
- if (use_spinlocks)
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
- return ret;
+ return __smem_get_entry(id, size, false);
}
EXPORT_SYMBOL(smem_get_entry);
@@ -341,6 +357,62 @@
return rc;
}
+/**
+ * smem_initialized_check - Reentrant check that smem has been initialized
+ *
+ * @returns: true if initialized, false if not.
+ */
+bool smem_initialized_check(void)
+{
+ static int checked;
+ static int is_inited;
+ unsigned long flags;
+ struct smem_shared *smem;
+ int *version_array;
+
+ if (likely(checked)) {
+ if (unlikely(!is_inited))
+ pr_err("%s: smem not initialized\n", __func__);
+ return is_inited;
+ }
+
+ spin_lock_irqsave(&smem_init_check_lock, flags);
+ if (checked) {
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ if (unlikely(!is_inited))
+ pr_err("%s: smem not initialized\n", __func__);
+ return is_inited;
+ }
+
+ smem = (void *)MSM_SHARED_RAM_BASE;
+
+ if (smem->heap_info.initialized != 1)
+ goto failed;
+ if (smem->heap_info.reserved != 0)
+ goto failed;
+
+ version_array = __smem_find(SMEM_VERSION_INFO, SMEM_VERSION_INFO_SIZE,
+ true);
+ if (version_array == NULL)
+ goto failed;
+ if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16)
+ goto failed;
+
+ is_inited = 1;
+ checked = 1;
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ return is_inited;
+
+failed:
+ is_inited = 0;
+ checked = 1;
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ pr_err("%s: bootloader failure detected, shared memory not inited\n",
+ __func__);
+ return is_inited;
+}
+EXPORT_SYMBOL(smem_initialized_check);
+
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 b631e7c..c4f9a77 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -71,4 +71,6 @@
* spinlock init code appears non-reentrant
*/
int init_smem_remote_spinlock(void);
+
+bool smem_initialized_check(void);
#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index b956649..a5e04cd 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -137,6 +137,7 @@
* @dentry: debugfs directory for this device
* @do_ramdump_on_put: ramdump on subsystem_put() if true
* @err_ready: completion variable to record error ready from subsystem
+ * @crashed: indicates if subsystem has crashed
*/
struct subsys_device {
struct subsys_desc *desc;
@@ -160,6 +161,7 @@
struct miscdevice misc_dev;
char miscdevice_name[32];
struct completion err_ready;
+ bool crashed;
};
static struct subsys_device *to_subsys(struct device *d)
@@ -427,8 +429,10 @@
ret = wait_for_completion_timeout(&subsys->err_ready,
msecs_to_jiffies(10000));
- if (!ret)
+ if (!ret) {
+ pr_err("[%s]: Error ready timed out\n", subsys->desc->name);
return -ETIMEDOUT;
+ }
return 0;
}
@@ -811,6 +815,15 @@
}
EXPORT_SYMBOL(subsystem_crashed);
+void subsys_set_crash_status(struct subsys_device *dev, bool crashed)
+{
+ dev->crashed = true;
+}
+
+bool subsys_get_crash_status(struct subsys_device *dev)
+{
+ return dev->crashed;
+}
#ifdef CONFIG_DEBUG_FS
static ssize_t subsys_debugfs_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
diff --git a/arch/arm/mach-msm/wallclk.c b/arch/arm/mach-msm/wallclk.c
new file mode 100644
index 0000000..9624795
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk.c
@@ -0,0 +1,475 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/hrtimer.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#include <mach/msm_iomap.h>
+
+#include "wallclk.h"
+
+#define WALLCLK_MODULE_NAME "wallclk"
+#define WALLCLK_MODULE_NAME_LEN 10
+
+#define FLAG_WALLCLK_INITED 0x1
+#define FLAG_WALLCLK_SFN_REF_SET 0x2
+#define FLAG_WALLCLK_ENABLED 0x4
+
+#define WALLCLK_TIMER_INTERVAL_NS 100000
+
+#define WALLCLK_SHARED_MEM_SIZE 1024
+#define ALIGN_64(addr) (((addr) + 7) & ~0x7)
+
+#define GPS_EPOCH_DIFF 315964800
+
+struct wallclk_cnt {
+ u32 pulse;
+ u32 clk;
+};
+
+struct wallclk_reg {
+ u32 ctrl;
+ u32 pulse_cnt;
+ u32 snapshot_clock_cnt;
+ u32 clock_cnt;
+ u32 __unused__[5];
+ u32 base_time0;
+ u32 base_time1;
+};
+
+struct wallclk_sm {
+ struct wallclk_reg reg;
+ u32 sfn_ref;
+};
+
+struct wallclk_cfg {
+ u32 ppns;
+ u32 clk_rate;
+ u32 clk_rate_v; /* clk_rate = clk_rate_v x clk_rate_p */
+ u32 clk_rate_p; /* power of 10 */
+ u32 ns_per_clk_rate_v;
+};
+
+struct wallclk {
+ struct wallclk_sm *shm;
+
+ struct wallclk_cfg cfg;
+
+ struct timespec tv;
+
+ struct hrtimer timer;
+ ktime_t interval;
+
+ spinlock_t lock;
+ u32 flags;
+
+ char name[WALLCLK_MODULE_NAME_LEN];
+};
+
+static struct wallclk wall_clk;
+
+static inline int is_valid_register(u32 offset)
+{
+ int rc = 0;
+
+ switch (offset) {
+ case CTRL_REG_OFFSET:
+ case PULSE_CNT_REG_OFFSET:
+ case CLK_CNT_SNAPSHOT_REG_OFFSET:
+ case CLK_CNT_REG_OFFSET:
+ case CLK_BASE_TIME0_OFFSET:
+ case CLK_BASE_TIME1_OFFSET:
+ rc = 1;
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+static inline void wallclk_ctrl_reg_set(struct wallclk *wclk, u32 v)
+{
+ struct wallclk_reg *reg = &wclk->shm->reg;
+
+ if (v & CTRL_ENABLE_MASK) {
+ if (!(wclk->flags & FLAG_WALLCLK_ENABLED)) {
+ getnstimeofday(&wclk->tv);
+ __raw_writel(0, ®->snapshot_clock_cnt);
+ __raw_writel(0, ®->clock_cnt);
+ __raw_writel(0, ®->pulse_cnt);
+ hrtimer_start(&wclk->timer,
+ wclk->interval,
+ HRTIMER_MODE_REL);
+ wclk->flags |= FLAG_WALLCLK_ENABLED;
+ }
+ } else {
+ if (wclk->flags & FLAG_WALLCLK_ENABLED) {
+ hrtimer_cancel(&wclk->timer);
+ wclk->flags &= ~FLAG_WALLCLK_ENABLED;
+ }
+ }
+
+ __raw_writel(v, ®->ctrl);
+}
+
+static inline void wallclk_cfg_init(struct wallclk_cfg *cfg,
+ u32 ppns,
+ u32 clk_rate)
+{
+ cfg->ppns = ppns;
+ cfg->clk_rate = clk_rate;
+ cfg->clk_rate_v = clk_rate;
+ cfg->clk_rate_p = 1;
+ cfg->ns_per_clk_rate_v = 1000000000;
+
+ while (!(cfg->clk_rate_v % 10)) {
+ cfg->clk_rate_v /= 10;
+ cfg->clk_rate_p *= 10;
+ cfg->ns_per_clk_rate_v /= 10;
+ }
+}
+
+static inline struct timespec timestamp_convert(const struct timespec *tv)
+{
+ struct timespec rc;
+
+ rc.tv_sec = tv->tv_sec - GPS_EPOCH_DIFF;
+ rc.tv_nsec = tv->tv_nsec;
+
+ return rc;
+}
+
+static inline void timespec_delta_to_wclk_cnt(const struct timespec *tv,
+ const struct wallclk_cfg *cfg,
+ struct wallclk_cnt *wclk_cnt)
+{
+ long ns;
+
+ wclk_cnt->pulse = tv->tv_sec / cfg->ppns;
+ wclk_cnt->clk = (tv->tv_sec % cfg->ppns) * cfg->clk_rate;
+
+ ns = tv->tv_nsec;
+ while (ns >= cfg->ns_per_clk_rate_v) {
+ ns -= cfg->ns_per_clk_rate_v;
+ wclk_cnt->clk += cfg->clk_rate_v;
+ }
+
+ wclk_cnt->clk += (ns * cfg->clk_rate_v)/cfg->ns_per_clk_rate_v;
+}
+
+static inline u32 wallclk_cnt_to_sfn(const struct wallclk_cnt *cnt,
+ const struct wallclk_cfg *cfg)
+{
+ u32 sfn;
+ u32 delta, p;
+
+ sfn = SFN_PER_SECOND * cnt->pulse * cfg->ppns;
+ if (cfg->clk_rate_p > 100) {
+ p = cfg->clk_rate_p/100;
+ delta = cnt->clk/(cfg->clk_rate_v * p);
+ } else {
+ p = 100/cfg->clk_rate_p;
+ delta = (cnt->clk * p)/cfg->clk_rate_v;
+ }
+ sfn += delta;
+
+ return sfn;
+}
+
+static void update_wallclk(struct wallclk *wclk)
+{
+ struct timespec tv;
+ struct timespec delta_tv;
+ struct wallclk_cnt cnt;
+ struct wallclk_reg *reg = &wclk->shm->reg;
+
+ spin_lock(&wclk->lock);
+ getnstimeofday(&tv);
+ delta_tv = timespec_sub(tv, wclk->tv);
+ timespec_delta_to_wclk_cnt(&delta_tv, &wclk->cfg, &cnt);
+ __raw_writel(cnt.pulse, ®->pulse_cnt);
+ __raw_writel(cnt.clk, ®->clock_cnt);
+ __raw_writel(cnt.clk, ®->snapshot_clock_cnt);
+
+ spin_unlock(&wclk->lock);
+}
+
+static int set_sfn(struct wallclk *wclk, u16 sfn)
+{
+ int rc = 0;
+ struct wallclk_reg *reg = &wclk->shm->reg;
+ u32 v;
+ struct timespec ts;
+
+ if (sfn > MAX_SFN) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (!(wclk->flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wclk->lock);
+
+ v = __raw_readl(®->ctrl);
+ wallclk_ctrl_reg_set(wclk, v & ~CTRL_ENABLE_MASK);
+
+ getnstimeofday(&wclk->tv);
+ ts = timestamp_convert(&wclk->tv);
+ __raw_writel(ts.tv_sec, ®->base_time0);
+ __raw_writel(ts.tv_nsec, ®->base_time1);
+
+ wclk->shm->sfn_ref = sfn;
+ wclk->flags |= FLAG_WALLCLK_SFN_REF_SET;
+
+ __raw_writel(0, ®->pulse_cnt);
+ __raw_writel(0, ®->clock_cnt);
+ __raw_writel(0, ®->snapshot_clock_cnt);
+ hrtimer_start(&wclk->timer, wclk->interval, HRTIMER_MODE_REL);
+ wclk->flags |= FLAG_WALLCLK_ENABLED;
+ __raw_writel(v | CTRL_ENABLE_MASK, ®->ctrl);
+
+ spin_unlock_bh(&wclk->lock);
+
+out:
+ return rc;
+}
+
+static int get_sfn(struct wallclk *wclk)
+{
+ struct wallclk_cnt cnt;
+ int rc = 0;
+ u32 sfn;
+
+ if (!(wclk->flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wclk->lock);
+
+ if (!(wclk->flags & FLAG_WALLCLK_ENABLED) ||
+ !(wclk->flags & FLAG_WALLCLK_SFN_REF_SET)) {
+ rc = -EIO;
+ goto unlock;
+ }
+
+ cnt.pulse = __raw_readl(&(wclk->shm->reg.pulse_cnt));
+ cnt.clk = __raw_readl(&(wclk->shm->reg.clock_cnt));
+ sfn = wallclk_cnt_to_sfn(&cnt, &wclk->cfg);
+
+ sfn += wclk->shm->sfn_ref;
+ rc = sfn & MAX_SFN;
+
+unlock:
+ spin_unlock_bh(&wclk->lock);
+out:
+ return rc;
+}
+
+enum hrtimer_restart wallclk_timer_cb(struct hrtimer *timer)
+{
+ update_wallclk(&wall_clk);
+ hrtimer_forward_now(timer, wall_clk.interval);
+ return HRTIMER_RESTART;
+}
+
+int wallclk_set_sfn(u16 sfn)
+{
+ return set_sfn(&wall_clk, sfn);
+}
+EXPORT_SYMBOL_GPL(wallclk_set_sfn);
+
+int wallclk_get_sfn(void)
+{
+ return get_sfn(&wall_clk);
+}
+EXPORT_SYMBOL_GPL(wallclk_get_sfn);
+
+int wallclk_set_sfn_ref(u16 sfn)
+{
+ int rc = 0;
+
+ if (sfn > MAX_SFN) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wall_clk.lock);
+
+ wall_clk.shm->sfn_ref = sfn;
+ wall_clk.flags |= FLAG_WALLCLK_SFN_REF_SET;
+
+ spin_unlock_bh(&wall_clk.lock);
+
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_set_sfn_ref);
+
+int wallclk_get_sfn_ref(void)
+{
+ int rc = 0;
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wall_clk.lock);
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_SFN_REF_SET)) {
+ rc = -EAGAIN;
+ goto unlock;
+ }
+ rc = wall_clk.shm->sfn_ref;
+
+unlock:
+ spin_unlock_bh(&wall_clk.lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_get_sfn_ref);
+
+int wallclk_reg_read(u32 offset, u32 *p)
+{
+ int rc = 0;
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ if (!is_valid_register(offset)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ spin_lock_bh(&wall_clk.lock);
+ *p = __raw_readl((char *)&wall_clk.shm->reg + offset);
+ spin_unlock_bh(&wall_clk.lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_reg_read);
+
+int wallclk_reg_write(u32 offset, u32 val)
+{
+ int rc = 0;
+ char *p;
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ p = (char *)&wall_clk.shm->reg;
+
+ spin_lock_bh(&wall_clk.lock);
+ switch (offset) {
+ case CTRL_REG_OFFSET:
+ wallclk_ctrl_reg_set(&wall_clk, val);
+ break;
+ case PULSE_CNT_REG_OFFSET:
+ case CLK_BASE_TIME0_OFFSET:
+ case CLK_BASE_TIME1_OFFSET:
+ __raw_writel(val, p + offset);
+ break;
+ case CLK_CNT_REG_OFFSET:
+ __raw_writel(val, p + CLK_CNT_REG_OFFSET);
+ __raw_writel(val, p + CLK_CNT_SNAPSHOT_REG_OFFSET);
+ break;
+ case CLK_CNT_SNAPSHOT_REG_OFFSET:
+ rc = -EIO;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ spin_unlock_bh(&wall_clk.lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_reg_write);
+
+static int __init wallclk_init(void)
+{
+ int rc = 0;
+ u32 addr;
+
+ memset(&wall_clk, 0, sizeof(wall_clk));
+
+ addr = (u32)MSM_SHARED_RAM_BASE + MSM_SHARED_RAM_SIZE -
+ WALLCLK_SHARED_MEM_SIZE;
+ wall_clk.shm = (struct wallclk_sm *)ALIGN_64(addr);
+
+ __raw_writel(0, &(wall_clk.shm->reg.ctrl));
+ __raw_writel(0, &(wall_clk.shm->reg.pulse_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.snapshot_clock_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.clock_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.clock_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.base_time0));
+ __raw_writel(0, &(wall_clk.shm->reg.base_time1));
+
+ wall_clk.shm->sfn_ref = 0;
+
+ wallclk_cfg_init(&wall_clk.cfg, PPNS_PULSE, CLK_RATE);
+
+ strlcpy(wall_clk.name, WALLCLK_MODULE_NAME, WALLCLK_MODULE_NAME_LEN);
+
+ hrtimer_init(&wall_clk.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ wall_clk.timer.function = wallclk_timer_cb;
+ wall_clk.interval = ns_to_ktime(WALLCLK_TIMER_INTERVAL_NS);
+ spin_lock_init(&wall_clk.lock);
+
+ wall_clk.flags |= FLAG_WALLCLK_INITED;
+
+ printk(KERN_INFO "%s: clk_rate=%u ppns=%u clk_reg_addr=0x%x\n",
+ wall_clk.name, wall_clk.cfg.clk_rate, wall_clk.cfg.ppns,
+ (int)(&wall_clk.shm->reg));
+ return rc;
+}
+
+static void __exit wallclk_exit(void)
+{
+ if (wall_clk.flags & FLAG_WALLCLK_INITED) {
+ spin_lock_bh(&wall_clk.lock);
+ wallclk_ctrl_reg_set(&wall_clk, 0);
+ wall_clk.flags = 0;
+ spin_unlock_bh(&wall_clk.lock);
+ }
+}
+
+module_init(wallclk_init);
+module_exit(wallclk_exit);
+
+MODULE_DESCRIPTION("Wall clock");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wallclk.h b/arch/arm/mach-msm/wallclk.h
new file mode 100644
index 0000000..1794395
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk.h
@@ -0,0 +1,46 @@
+/* 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.
+ *
+ */
+#ifndef _WALLCLK_H
+#define _WALLCLK_H
+
+/* wallclock register offset */
+#define CTRL_REG_OFFSET 0x0
+#define PULSE_CNT_REG_OFFSET 0x4
+#define CLK_CNT_SNAPSHOT_REG_OFFSET 0x8
+#define CLK_CNT_REG_OFFSET 0xC
+#define CLK_BASE_TIME0_OFFSET 0x24
+#define CLK_BASE_TIME1_OFFSET 0x28
+
+/* ctrl register bitmap */
+#define CTRL_TIME_SRC_POS 0
+#define CTRL_TIME_SRC_MASK 0x0000000F
+#define CTRL_SW_BITS_POS 4
+#define CTRL_SW_BITS_MASK 0x7FFFFFF0
+#define CTRL_ENA_DIS_POS 31
+#define CTRL_ENABLE_MASK 0x80000000
+
+/* clock rate from time source */
+#define CLK_RATE 122880000 /* 122.88 Mhz */
+#define PPNS_PULSE 2 /* PP2S */
+
+#define MAX_SFN 1023
+#define SFN_PER_SECOND 100
+
+extern int wallclk_set_sfn(u16 sfn);
+extern int wallclk_get_sfn(void);
+extern int wallclk_set_sfn_ref(u16 sfn);
+extern int wallclk_get_sfn_ref(void);
+extern int wallclk_reg_read(u32 offset, u32 *p);
+extern int wallclk_reg_write(u32 offset, u32 value);
+
+#endif /* _WALLCLK_H */
diff --git a/arch/arm/mach-msm/wallclk_sysfs.c b/arch/arm/mach-msm/wallclk_sysfs.c
new file mode 100644
index 0000000..9274137
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk_sysfs.c
@@ -0,0 +1,308 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#include "wallclk.h"
+
+#define WALLCLK_SYSFS_MODULE_NAME "wallclk_sysfs"
+
+static struct kobject *wallclk_kobj;
+
+static ssize_t sfn_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ int rc;
+
+ rc = wallclk_get_sfn();
+ if (rc < 0)
+ return rc;
+ return snprintf(buf, 10, "%d\n", rc);
+}
+
+static ssize_t sfn_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ u16 sfn;
+ int rc;
+
+ if (kstrtou16(buf, 0, &sfn)) {
+ printk(KERN_ERR "%s: sfn input is not a valid u16 value\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = wallclk_set_sfn(sfn);
+
+ if (rc) {
+ printk(KERN_ERR "%s: fail to set sfn\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ goto out;
+ }
+ rc = count;
+
+out:
+ return rc;
+}
+
+static struct kobj_attribute sfn_attribute =
+ __ATTR(sfn, 0666, sfn_show, sfn_store);
+
+static ssize_t sfn_ref_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ int rc;
+
+ rc = wallclk_get_sfn_ref();
+ if (rc < 0)
+ return rc;
+ return snprintf(buf, 10, "%d\n", rc);
+}
+
+static ssize_t sfn_ref_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ u16 sfn_ref;
+ int rc;
+
+ if (kstrtou16(buf, 0, &sfn_ref)) {
+ printk(KERN_ERR "%s: sfn_ref input is not a valid u16 value\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = wallclk_set_sfn_ref(sfn_ref);
+
+ if (rc) {
+ printk(KERN_ERR "%s: fail to set sfn_ref\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ goto out;
+ }
+ rc = count;
+
+out:
+ return rc;
+}
+
+static struct kobj_attribute sfn_ref_attribute =
+ __ATTR(sfn_ref, 0666, sfn_ref_show, sfn_ref_store);
+
+static ssize_t reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf,
+ u32 offset)
+{
+ int rc;
+ u32 val;
+
+ rc = wallclk_reg_read(offset, &val);
+ if (rc)
+ return rc;
+
+ return snprintf(buf, 20, "%08x\n", val);
+}
+
+static ssize_t reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ const size_t count,
+ u32 offset)
+{
+ u32 v;
+ int rc;
+
+ if (kstrtou32(buf, 0, &v)) {
+ printk(KERN_ERR "%s: input is not a valid u32 value\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = wallclk_reg_write(offset, v);
+
+ if (rc) {
+ printk(KERN_ERR "%s: fail to set register(offset=0x%x)\n",
+ WALLCLK_SYSFS_MODULE_NAME, offset);
+ goto out;
+ }
+ rc = count;
+
+out:
+ return rc;
+}
+
+static ssize_t ctrl_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CTRL_REG_OFFSET);
+}
+
+static ssize_t ctrl_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ const size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CTRL_REG_OFFSET);
+}
+
+static struct kobj_attribute ctrl_reg_attribute =
+ __ATTR(ctrl_reg, 0666, ctrl_reg_show, ctrl_reg_store);
+
+static ssize_t basetime0_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_BASE_TIME0_OFFSET);
+}
+
+static ssize_t basetime0_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CLK_BASE_TIME0_OFFSET);
+}
+
+static struct kobj_attribute basetime0_reg_attribute =
+ __ATTR(base_time0_reg, 0666, basetime0_reg_show, basetime0_reg_store);
+
+static ssize_t basetime1_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_BASE_TIME1_OFFSET);
+}
+
+static ssize_t basetime1_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CLK_BASE_TIME1_OFFSET);
+}
+
+static struct kobj_attribute basetime1_reg_attribute =
+ __ATTR(base_time1_reg, 0666, basetime1_reg_show, basetime1_reg_store);
+
+static ssize_t pulse_cnt_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, PULSE_CNT_REG_OFFSET);
+}
+
+static ssize_t pulse_cnt_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, PULSE_CNT_REG_OFFSET);
+}
+
+static struct kobj_attribute pulse_cnt_reg_attribute =
+ __ATTR(pulse_cnt_reg, 0666, pulse_cnt_reg_show, pulse_cnt_reg_store);
+
+static ssize_t clk_cnt_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_CNT_REG_OFFSET);
+}
+
+static ssize_t clk_cnt_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CLK_CNT_REG_OFFSET);
+}
+
+static struct kobj_attribute clk_cnt_reg_attribute =
+ __ATTR(clock_cnt_reg, 0666, clk_cnt_reg_show, clk_cnt_reg_store);
+
+static ssize_t clk_cnt_snapshot_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_CNT_SNAPSHOT_REG_OFFSET);
+}
+
+static struct kobj_attribute clk_cnt_snapshot_reg_attribute =
+ __ATTR(clock_cnt_snapshot_reg, 0444, clk_cnt_snapshot_reg_show, NULL);
+
+static struct attribute *wallclk_attrs[] = {
+ &sfn_attribute.attr,
+ &sfn_ref_attribute.attr,
+ &ctrl_reg_attribute.attr,
+ &pulse_cnt_reg_attribute.attr,
+ &clk_cnt_snapshot_reg_attribute.attr,
+ &clk_cnt_reg_attribute.attr,
+ &basetime0_reg_attribute.attr,
+ &basetime1_reg_attribute.attr,
+ NULL
+};
+
+static struct attribute_group wallclk_attr_group = {
+ .attrs = wallclk_attrs,
+};
+
+static int __init wallclk_sysfs_init(void)
+{
+ int rc;
+
+ wallclk_kobj = kobject_create_and_add("wallclk", kernel_kobj);
+ if (!wallclk_kobj) {
+ printk(KERN_ERR "%s: failed to create kobject\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = sysfs_create_group(wallclk_kobj, &wallclk_attr_group);
+ if (rc) {
+ kobject_put(wallclk_kobj);
+ printk(KERN_ERR "%s: failed to create sysfs group\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ }
+
+out:
+ return rc;
+}
+
+static void __exit wallclk_sysfs_exit(void)
+{
+ kobject_put(wallclk_kobj);
+}
+
+module_init(wallclk_sysfs_init);
+module_exit(wallclk_sysfs_exit);
+
+MODULE_DESCRIPTION("Wall clock SysFS");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 682d876..fa0e9d7 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -58,14 +58,14 @@
pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
read_bytes, dci_pkt_len);
/* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
- DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
+ DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1); */
recv_pkt_cmd_code = *(uint8_t *)(buf+4);
if (recv_pkt_cmd_code == LOG_CMD_CODE)
extract_dci_log(buf+4);
else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
extract_dci_events(buf+4);
else
- extract_dci_pkt_rsp(buf); /* pkt response */
+ extract_dci_pkt_rsp(smd_info, buf); /* pkt response */
read_bytes += 5 + dci_pkt_len;
buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
}
@@ -83,7 +83,7 @@
return 0;
}
-void extract_dci_pkt_rsp(unsigned char *buf)
+void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf)
{
int i = 0, index = -1, cmd_code_len = 1;
int curr_client_pid = 0, write_len;
@@ -95,6 +95,7 @@
if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
cmd_code_len = 4; /* delayed response */
write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
+
pr_debug("diag: len = %d\n", write_len);
/* look up DCI client with tag */
for (i = 0; i < dci_max_reg; i++) {
@@ -139,8 +140,7 @@
buf+4+cmd_code_len, write_len);
entry->data_len += write_len;
/* delete immediate response entry */
- if (driver->smd_dci[MODEM_DATA].
- buf_in_1[8+cmd_code_len] != 0x80)
+ if (smd_info->buf_in_1[8+cmd_code_len] != 0x80)
driver->req_tracking_tbl[index].pid = 0;
}
}
@@ -372,39 +372,26 @@
} /* end of loop for all DCI clients */
}
-static int diag_dci_probe(struct platform_device *pdev)
-{
- int err = 0;
- int index;
-
- if (pdev->id == SMD_APPS_MODEM) {
- index = MODEM_DATA;
- err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
- &driver->smd_dci[index],
- diag_smd_notify);
- driver->smd_dci[index].ch_save =
- driver->smd_dci[index].ch;
- if (err)
- pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
- __func__, pdev->id, err);
- }
-
- return err;
-}
-
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index)
{
- int i;
- int status = 0;
+ int i, status = 0;
+ unsigned int read_len = 0;
- /* remove UID from user space pkt before sending to peripheral */
- buf = buf + 4;
- if (len > APPS_BUF_SIZE - 10) {
- pr_err("diag: dci: buffer overwrite possible since payload bigger than buf size\n");
+ /* The first 4 bytes is the uid tag and the next four bytes is
+ the minmum packet length of a request packet */
+ if (len < DCI_PKT_REQ_MIN_LEN) {
+ pr_err("diag: dci: Invalid pkt len %d in %s\n", len, __func__);
return -EIO;
}
- len = len - 4;
+ if (len > APPS_BUF_SIZE - 10) {
+ pr_err("diag: dci: Invalid payload length in %s\n", __func__);
+ return -EIO;
+ }
+ /* remove UID from user space pkt before sending to peripheral*/
+ buf = buf + sizeof(int);
+ read_len += sizeof(int);
+ len = len - sizeof(int);
mutex_lock(&driver->dci_mutex);
/* prepare DCI packet */
driver->apps_dci_buf[0] = CONTROL_CHAR; /* start */
@@ -415,12 +402,21 @@
driver->req_tracking_tbl[index].tag;
for (i = 0; i < len; i++)
driver->apps_dci_buf[i+9] = *(buf+i);
+ read_len += len;
driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
+ if ((read_len + 9) >= USER_SPACE_DATA) {
+ pr_err("diag: dci: Invalid length while forming dci pkt in %s",
+ __func__);
+ return -EIO;
+ }
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
- if (entry.client_id == driver->smd_dci[i].peripheral) {
- if (driver->smd_dci[i].ch) {
- smd_write(driver->smd_dci[i].ch,
+ struct diag_smd_info *smd_info = driver->separate_cmdrsp[i] ?
+ &driver->smd_dci_cmd[i] :
+ &driver->smd_dci[i];
+ if (entry.client_id == smd_info->peripheral) {
+ if (smd_info->ch) {
+ smd_write(smd_info->ch,
driver->apps_dci_buf, len + 10);
status = DIAG_DCI_NO_ERROR;
}
@@ -466,10 +462,10 @@
{
unsigned char *temp = buf;
uint16_t subsys_cmd_code, log_code, item_num;
- int subsys_id, cmd_code, ret = -1, index = -1, found = 0, read_len = 0;
+ int subsys_id, cmd_code, ret = -1, index = -1, found = 0;
struct diag_master_table entry;
int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
- unsigned int byte_index;
+ unsigned int byte_index, read_len = 0;
uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
uint8_t *event_mask_ptr;
@@ -479,15 +475,24 @@
return DIAG_DCI_SEND_DATA_FAIL;
}
+ if (!temp) {
+ pr_err("diag: Invalid buffer in %s\n", __func__);
+ }
+
/* This is Pkt request/response transaction */
if (*(int *)temp > 0) {
+ if (len < DCI_PKT_REQ_MIN_LEN || len > USER_SPACE_DATA) {
+ pr_err("diag: dci: Invalid length %d len in %s", len,
+ __func__);
+ return -EIO;
+ }
/* enter this UID into kernel table and return index */
index = diag_register_dci_transaction(*(int *)temp);
if (index < 0) {
pr_alert("diag: registering new DCI transaction failed\n");
return DIAG_DCI_NO_REG;
}
- temp += 4;
+ temp += sizeof(int);
/*
* Check for registered peripheral and fwd pkt to
* appropriate proc
@@ -497,7 +502,12 @@
subsys_id = (int)(*(char *)temp);
temp++;
subsys_cmd_code = *(uint16_t *)temp;
- temp += 2;
+ temp += sizeof(uint16_t);
+ read_len += sizeof(int) + 2 + sizeof(uint16_t);
+ if (read_len >= USER_SPACE_DATA) {
+ pr_err("diag: dci: Invalid length in %s\n", __func__);
+ return -EIO;
+ }
pr_debug("diag: %d %d %d", cmd_code, subsys_id,
subsys_cmd_code);
for (i = 0; i < diag_max_reg; i++) {
@@ -531,6 +541,12 @@
}
}
} else if (*(int *)temp == DCI_LOG_TYPE) {
+ /* Minimum length of a log mask config is 12 + 2 bytes for
+ atleast one log code to be set or reset */
+ if (len < DCI_LOG_CON_MIN_LEN || len > USER_SPACE_DATA) {
+ pr_err("diag: dci: Invalid length in %s\n", __func__);
+ return -EIO;
+ }
/* find client id and table */
i = diag_dci_find_client_index(current->tgid);
if (i == DCI_CLIENT_INDEX_INVALID) {
@@ -538,21 +554,33 @@
return ret;
}
/* Extract each log code and put in client table */
- temp += 4;
- read_len += 4;
+ temp += sizeof(int);
+ read_len += sizeof(int);
set_mask = *(int *)temp;
- temp += 4;
- read_len += 4;
+ temp += sizeof(int);
+ read_len += sizeof(int);
num_codes = *(int *)temp;
- temp += 4;
- read_len += 4;
+ temp += sizeof(int);
+ read_len += sizeof(int);
+
+ if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) {
+ pr_err("diag: dci: Invalid number of log codes %d\n",
+ num_codes);
+ return -EIO;
+ }
head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
+ if (!head_log_mask_ptr) {
+ pr_err("diag: dci: Invalid Log mask pointer in %s\n",
+ __func__);
+ return -ENOMEM;
+ }
pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
count = 0; /* iterator for extracting log codes */
while (count < num_codes) {
if (read_len >= USER_SPACE_DATA) {
- pr_err("diag: dci: Log type, possible buffer overflow\n");
+ pr_err("diag: dci: Invalid length for log type in %s",
+ __func__);
return -EIO;
}
log_code = *(uint16_t *)temp;
@@ -606,6 +634,12 @@
/* send updated mask to peripherals */
ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
+ /* Minimum length of a event mask config is 12 + 4 bytes for
+ atleast one event id to be set or reset. */
+ if (len < DCI_EVENT_CON_MIN_LEN || len > USER_SPACE_DATA) {
+ pr_err("diag: dci: Invalid length in %s\n", __func__);
+ return -EIO;
+ }
/* find client id and table */
i = diag_dci_find_client_index(current->tgid);
if (i == DCI_CLIENT_INDEX_INVALID) {
@@ -613,21 +647,36 @@
return ret;
}
/* Extract each log code and put in client table */
- temp += 4;
- read_len += 4;
+ temp += sizeof(int);
+ read_len += sizeof(int);
set_mask = *(int *)temp;
- temp += 4;
- read_len += 4;
+ temp += sizeof(int);
+ read_len += sizeof(int);
num_codes = *(int *)temp;
- temp += 4;
- read_len += 4;
+ temp += sizeof(int);
+ read_len += sizeof(int);
+
+ /* Check for positive number of event ids. Also, the number of
+ event ids should fit in the buffer along with set_mask and
+ num_codes which are 4 bytes each */
+ if (num_codes == 0 || (num_codes >= (USER_SPACE_DATA - 8)/2)) {
+ pr_err("diag: dci: Invalid number of event ids %d\n",
+ num_codes);
+ return -EIO;
+ }
event_mask_ptr = driver->dci_client_tbl[i].dci_event_mask;
+ if (!event_mask_ptr) {
+ pr_err("diag: dci: Invalid event mask pointer in %s\n",
+ __func__);
+ return -ENOMEM;
+ }
pr_debug("diag: head of dci event mask %p\n", event_mask_ptr);
count = 0; /* iterator for extracting log codes */
while (count < num_codes) {
if (read_len >= USER_SPACE_DATA) {
- pr_err("diag: dci: Event type, possible buffer overflow\n");
+ pr_err("diag: dci: Invalid length for event type in %s",
+ __func__);
return -EIO;
}
event_id = *(int *)temp;
@@ -1000,6 +1049,49 @@
memset(tbl_buf, 0, 512);
}
+static int diag_dci_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ int index;
+
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ err = smd_open("DIAG_2",
+ &driver->smd_dci[index].ch,
+ &driver->smd_dci[index],
+ diag_smd_notify);
+ driver->smd_dci[index].ch_save =
+ driver->smd_dci[index].ch;
+ if (err)
+ pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+ __func__, pdev->id, err);
+ }
+
+ return err;
+}
+
+static int diag_dci_cmd_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ int index;
+
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ err = smd_named_open_on_edge("DIAG_2_CMD",
+ pdev->id,
+ &driver->smd_dci_cmd[index].ch,
+ &driver->smd_dci_cmd[index],
+ diag_smd_notify);
+ driver->smd_dci_cmd[index].ch_save =
+ driver->smd_dci_cmd[index].ch;
+ if (err)
+ pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+ __func__, pdev->id, err);
+ }
+
+ return err;
+}
+
static int diag_dci_runtime_suspend(struct device *dev)
{
dev_dbg(dev, "pm_runtime: suspending...\n");
@@ -1020,9 +1112,18 @@
struct platform_driver msm_diag_dci_driver = {
.probe = diag_dci_probe,
.driver = {
- .name = "DIAG_2",
- .owner = THIS_MODULE,
- .pm = &diag_dci_dev_pm_ops,
+ .name = "DIAG_2",
+ .owner = THIS_MODULE,
+ .pm = &diag_dci_dev_pm_ops,
+ },
+};
+
+struct platform_driver msm_diag_dci_cmd_driver = {
+ .probe = diag_dci_cmd_probe,
+ .driver = {
+ .name = "DIAG_2_CMD",
+ .owner = THIS_MODULE,
+ .pm = &diag_dci_dev_pm_ops,
},
};
@@ -1040,12 +1141,21 @@
mutex_init(&dci_health_mutex);
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
- success = diag_smd_constructor(&driver->smd_dci[i],
- i, SMD_DCI_TYPE);
+ success = diag_smd_constructor(&driver->smd_dci[i], i,
+ SMD_DCI_TYPE);
if (!success)
goto err;
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_dci_cmd[i],
+ i, SMD_DCI_CMD_TYPE);
+ if (!success)
+ goto err;
+ }
+ }
+
if (driver->req_tracking_tbl == NULL) {
driver->req_tracking_tbl = kzalloc(dci_max_reg *
sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
@@ -1069,6 +1179,13 @@
pr_err("diag: Could not register DCI driver\n");
goto err;
}
+ if (driver->supports_separate_cmdrsp) {
+ success = platform_driver_register(&msm_diag_dci_cmd_driver);
+ if (success) {
+ pr_err("diag: Could not register DCI cmd driver\n");
+ goto err;
+ }
+ }
return DIAG_DCI_NO_ERROR;
err:
pr_err("diag: Could not initialize diag DCI buffers");
@@ -1077,6 +1194,11 @@
kfree(driver->apps_dci_buf);
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
diag_smd_destructor(&driver->smd_dci[i]);
+
+ if (driver->supports_separate_cmdrsp)
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_dci_cmd[i]);
+
if (driver->diag_dci_wq)
destroy_workqueue(driver->diag_dci_wq);
return DIAG_DCI_NO_REG;
@@ -1096,6 +1218,12 @@
kfree(driver->dci_client_tbl[i].dci_data);
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_dci_cmd[i]);
+
+ platform_driver_unregister(&msm_diag_dci_cmd_driver);
+ }
kfree(driver->req_tracking_tbl);
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 260cdf3..d530de9 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -24,6 +24,9 @@
#define DISABLE_LOG_MASK 0
#define MAX_EVENT_SIZE 512
#define DCI_CLIENT_INDEX_INVALID -1
+#define DCI_PKT_REQ_MIN_LEN 8
+#define DCI_LOG_CON_MIN_LEN 14
+#define DCI_EVENT_CON_MIN_LEN 16
/* 16 log code categories, each has:
@@ -95,7 +98,7 @@
int diag_process_dci_transaction(unsigned char *buf, int len);
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
-void extract_dci_pkt_rsp(unsigned char *buf);
+void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf);
int diag_dci_find_client_index(int client_id);
/* DCI Log streaming functions */
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 76490c8..71eda68 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -44,12 +44,18 @@
"modem cntl_ch: 0x%x\n"
"lpass cntl_ch: 0x%x\n"
"riva cntl_ch: 0x%x\n"
+ "modem cmd ch: 0x%x\n"
+ "dci cmd ch: 0x%x\n"
"CPU Tools id: %d\n"
"Apps only: %d\n"
"Apps master: %d\n"
"Check Polling Response: %d\n"
"polling_reg_flag: %d\n"
"uses device tree: %d\n"
+ "supports separate cmdrsp: %d\n"
+ "Modem separate cmdrsp: %d\n"
+ "LPASS separate cmdrsp: %d\n"
+ "RIVA separate cmdrsp: %d\n"
"Modem in_busy_1: %d\n"
"Modem in_busy_2: %d\n"
"LPASS in_busy_1: %d\n"
@@ -57,6 +63,9 @@
"RIVA in_busy_1: %d\n"
"RIVA in_busy_2: %d\n"
"DCI Modem in_busy_1: %d\n"
+ "Modem CMD in_busy_1: %d\n"
+ "Modem CMD in_busy_2: %d\n"
+ "DCI CMD Modem in_busy_1: %d\n"
"logging_mode: %d\n",
(unsigned int)driver->smd_data[MODEM_DATA].ch,
(unsigned int)driver->smd_data[LPASS_DATA].ch,
@@ -65,12 +74,18 @@
(unsigned int)driver->smd_cntl[MODEM_DATA].ch,
(unsigned int)driver->smd_cntl[LPASS_DATA].ch,
(unsigned int)driver->smd_cntl[WCNSS_DATA].ch,
+ (unsigned int)driver->smd_cmd[MODEM_DATA].ch,
+ (unsigned int)driver->smd_dci_cmd[MODEM_DATA].ch,
chk_config_get_id(),
chk_apps_only(),
chk_apps_master(),
chk_polling_response(),
driver->polling_reg_flag,
driver->use_device_tree,
+ driver->supports_separate_cmdrsp,
+ driver->separate_cmdrsp[MODEM_DATA],
+ driver->separate_cmdrsp[LPASS_DATA],
+ driver->separate_cmdrsp[WCNSS_DATA],
driver->smd_data[MODEM_DATA].in_busy_1,
driver->smd_data[MODEM_DATA].in_busy_2,
driver->smd_data[LPASS_DATA].in_busy_1,
@@ -78,6 +93,9 @@
driver->smd_data[WCNSS_DATA].in_busy_1,
driver->smd_data[WCNSS_DATA].in_busy_2,
driver->smd_dci[MODEM_DATA].in_busy_1,
+ driver->smd_cmd[MODEM_DATA].in_busy_1,
+ driver->smd_cmd[MODEM_DATA].in_busy_2,
+ driver->smd_dci_cmd[MODEM_DATA].in_busy_1,
driver->logging_mode);
#ifdef CONFIG_DIAG_OVER_USB
@@ -181,7 +199,7 @@
}
buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
- if (!buf) {
+ if (ZERO_OR_NULL_PTR(buf)) {
pr_err("diag: %s, Error allocating memory\n", __func__);
return -ENOMEM;
}
@@ -249,7 +267,7 @@
}
buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
- if (!buf) {
+ if (ZERO_OR_NULL_PTR(buf)) {
pr_err("diag: %s, Error allocating memory\n", __func__);
return -ENOMEM;
}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 04c3300..5aed793 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -27,7 +27,6 @@
#define MAX_SSID_PER_RANGE 100
#define FEATURE_MASK_LEN_BYTES 1
-#define APPS_RESPOND_LOG_ON_DEMAND 0x04
struct mask_info {
int equip_id;
@@ -48,13 +47,6 @@
msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int); \
} while (0)
-#define WAIT_FOR_SMD(num_delays, delay_time) \
-do { \
- int count; \
- for (count = 0; count < (num_delays); count++) \
- udelay((delay_time)); \
-} while (0)
-
static void diag_print_mask_table(void)
{
/* Enable this to print mask table when updated */
@@ -312,7 +304,7 @@
smd_info->peripheral);
diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
- diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
+ diag_send_feature_mask_update(smd_info);
if (smd_info->notify_context == SMD_EVENT_OPEN)
diag_send_diag_mode_update_by_smd(smd_info, MODE_REALTIME);
@@ -352,7 +344,7 @@
header_size + size);
if (wr_size == -ENOMEM) {
retry_count++;
- WAIT_FOR_SMD(5, 2000);
+ usleep_range(10000, 10100);
} else
break;
}
@@ -397,7 +389,7 @@
wr_size = smd_write(ch, buf, header_size + num_bytes);
if (wr_size == -ENOMEM) {
retry_count++;
- WAIT_FOR_SMD(5, 2000);
+ usleep_range(10000, 10100);
} else
break;
}
@@ -447,7 +439,7 @@
4*(driver->msg_mask->msg_mask_size));
if (size == -ENOMEM) {
retry_count++;
- WAIT_FOR_SMD(5, 2000);
+ usleep_range(10000, 10100);
} else
break;
}
@@ -468,12 +460,25 @@
mutex_unlock(&driver->diag_cntl_mutex);
}
-void diag_send_feature_mask_update(smd_channel_t *ch, int proc)
+void diag_send_feature_mask_update(struct diag_smd_info *smd_info)
{
void *buf = driver->buf_feature_mask_update;
int header_size = sizeof(struct diag_ctrl_feature_mask);
- int wr_size = -ENOMEM, retry_count = 0, timer;
+ int wr_size = -ENOMEM, retry_count = 0;
uint8_t feature_byte = 0;
+ int total_len = 0;
+
+ if (!smd_info) {
+ pr_err("diag: In %s, null smd info pointer\n",
+ __func__);
+ return;
+ }
+
+ if (!smd_info->ch) {
+ pr_err("diag: In %s, smd channel not open for peripheral: %d, type: %d\n",
+ __func__, smd_info->peripheral, smd_info->type);
+ return;
+ }
mutex_lock(&driver->diag_cntl_mutex);
/* send feature mask update */
@@ -482,27 +487,32 @@
driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
memcpy(buf, driver->feature_mask, header_size);
feature_byte |= F_DIAG_INT_FEATURE_MASK;
- feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
+ feature_byte |= F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+ feature_byte |= driver->supports_separate_cmdrsp ?
+ F_DIAG_REQ_RSP_CHANNEL : 0;
memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
+ total_len = header_size + FEATURE_MASK_LEN_BYTES;
- if (ch) {
- while (retry_count < 3) {
- wr_size = smd_write(ch, buf, header_size +
- FEATURE_MASK_LEN_BYTES);
- if (wr_size == -ENOMEM) {
- retry_count++;
- for (timer = 0; timer < 5; timer++)
- udelay(2000);
- } else
- break;
- }
- if (wr_size != header_size + FEATURE_MASK_LEN_BYTES)
- pr_err("diag: proc %d fail feature update %d, tried %d",
- proc, wr_size, header_size + FEATURE_MASK_LEN_BYTES);
- } else
- pr_err("diag: ch invalid, feature update on proc %d\n", proc);
+ while (retry_count < 3) {
+ wr_size = smd_write(smd_info->ch, buf, total_len);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ /*
+ * The smd channel is full. Delay while
+ * smd processes existing data and smd
+ * has memory become available. The delay
+ * of 10000 was determined empirically as
+ * best value to use.
+ */
+ usleep_range(10000, 10100);
+ } else
+ break;
+ }
+ if (wr_size != total_len)
+ pr_err("diag: In %s, peripheral %d fail feature update, size: %d, tried: %d",
+ __func__, smd_info->peripheral, wr_size, total_len);
+
mutex_unlock(&driver->diag_cntl_mutex);
-
}
int diag_process_apps_masks(unsigned char *buf, int len)
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 53f72e8..c66a4b6 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* 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
@@ -21,7 +21,7 @@
int ssid_last, int proc);
void diag_send_log_mask_update(smd_channel_t *, int);
void diag_mask_update_fn(struct work_struct *work);
-void diag_send_feature_mask_update(smd_channel_t *ch, int proc);
+void diag_send_feature_mask_update(struct diag_smd_info *smd_info);
int diag_process_apps_masks(unsigned char *buf, int len);
void diag_masks_init(void);
void diag_masks_exit(void);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 292a0be..b05bcef 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -82,12 +82,16 @@
#define MODE_NONREALTIME 0
#define NUM_SMD_DATA_CHANNELS 3
-#define NUM_SMD_CONTROL_CHANNELS 3
+#define NUM_SMD_CONTROL_CHANNELS NUM_SMD_DATA_CHANNELS
#define NUM_SMD_DCI_CHANNELS 1
+#define NUM_SMD_CMD_CHANNELS 1
+#define NUM_SMD_DCI_CMD_CHANNELS 1
#define SMD_DATA_TYPE 0
#define SMD_CNTL_TYPE 1
#define SMD_DCI_TYPE 2
+#define SMD_CMD_TYPE 3
+#define SMD_DCI_CMD_TYPE 4
/* Maximum number of pkt reg supported at initialization*/
extern int diag_max_reg;
@@ -221,6 +225,7 @@
struct diag_write_device *buf_tbl;
unsigned int buf_tbl_size;
int use_device_tree;
+ int supports_separate_cmdrsp;
/* DCI related variables */
struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
struct diag_dci_client_tbl *dci_client_tbl;
@@ -263,6 +268,9 @@
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
+ struct diag_smd_info smd_cmd[NUM_SMD_CMD_CHANNELS];
+ struct diag_smd_info smd_dci_cmd[NUM_SMD_DCI_CMD_CHANNELS];
+ int separate_cmdrsp[NUM_SMD_CONTROL_CHANNELS];
unsigned char *usb_buf_out;
unsigned char *apps_rsp_buf;
/* buffer for updating mask to peripherals */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 96e8b11..90a4154 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -595,7 +595,7 @@
}
head_params = kzalloc(pkt_params.count*sizeof(
struct bindpkt_params), GFP_KERNEL);
- if (!head_params) {
+ if (ZERO_OR_NULL_PTR(head_params)) {
pr_err("diag: unable to alloc memory\n");
return -ENOMEM;
} else
@@ -782,7 +782,7 @@
int diag_switch_logging(unsigned long ioarg)
{
- int i, temp, success = -EINVAL, status;
+ int temp = 0, success = -EINVAL, status = 0;
int temp_realtime_mode = driver->real_time_mode;
int requested_mode = (int)ioarg;
@@ -857,24 +857,13 @@
if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
== NO_LOGGING_MODE) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- }
+ diag_reset_smd_data(RESET_AND_NO_QUEUE);
diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
diag_cmp_logging_modes_diagfwd_bridge(temp,
driver->logging_mode);
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].
- diag_read_smd_work));
- }
+ diag_reset_smd_data(RESET_AND_QUEUE);
diag_cmp_logging_modes_sdio_pipe(temp,
driver->logging_mode);
diag_cmp_logging_modes_diagfwd_bridge(temp,
@@ -892,15 +881,7 @@
} else if (temp == USB_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
diagfwd_disconnect();
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].
- diag_read_smd_work));
- }
+ diag_reset_smd_data(RESET_AND_QUEUE);
diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
diag_cmp_logging_modes_diagfwd_bridge(temp,
driver->logging_mode);
@@ -964,9 +945,13 @@
return -EFAULT;
}
mutex_lock(&driver->dci_mutex);
- if (!(driver->num_dci_client))
+ if (!(driver->num_dci_client)) {
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
driver->smd_dci[i].in_busy_1 = 0;
+ if (driver->supports_separate_cmdrsp)
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+ driver->smd_dci_cmd[i].in_busy_1 = 0;
+ }
driver->num_dci_client++;
pr_debug("diag: In %s, id = %d\n",
__func__, driver->dci_client_id);
@@ -1206,7 +1191,7 @@
}
}
- /* copy modem data */
+ /* Copy peripheral data */
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
struct diag_smd_info *data = &driver->smd_data[i];
if (data->in_busy_1 == 1) {
@@ -1240,6 +1225,37 @@
data->in_busy_2 = 0;
}
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ struct diag_smd_info *data =
+ &driver->smd_cmd[i];
+ if (!driver->separate_cmdrsp[i])
+ continue;
+
+ if (data->in_busy_1 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (data->write_ptr_1->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(data->buf_in_1),
+ data->write_ptr_1->length);
+ data->in_busy_1 = 0;
+ }
+ if (data->in_busy_2 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (data->write_ptr_2->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(data->buf_in_2),
+ data->write_ptr_2->length);
+ data->in_busy_2 = 0;
+ }
+ }
+ }
#ifdef CONFIG_DIAG_SDIO_PIPE
/* copy 9K data over SDIO */
if (driver->in_busy_sdio == 1) {
@@ -1360,6 +1376,17 @@
queue_work(driver->diag_dci_wq,
&(driver->smd_dci[i].diag_read_smd_work));
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
+ if (!driver->separate_cmdrsp[i])
+ continue;
+ driver->smd_dci_cmd[i].in_busy_1 = 0;
+ if (driver->smd_dci_cmd[i].ch)
+ queue_work(driver->diag_dci_wq,
+ &(driver->smd_dci_cmd[i].
+ diag_read_smd_work));
+ }
+ }
goto exit;
}
exit:
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 9c2c8b1..6851fd8 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -321,6 +321,19 @@
{
struct diag_request *write_ptr_modem = NULL;
int *in_busy_ptr = 0;
+ int err = 0;
+
+ /*
+ * Do not process data on command channel if the
+ * channel is not designated to do so
+ */
+ if ((smd_info->type == SMD_CMD_TYPE) &&
+ !driver->separate_cmdrsp[smd_info->peripheral]) {
+ /* This print is for debugging */
+ pr_err("diag, In %s, received data on non-designated command channel: %d\n",
+ __func__, smd_info->peripheral);
+ return 0;
+ }
if (smd_info->buf_in_1 == buf) {
write_ptr_modem = smd_info->write_ptr_1;
@@ -335,7 +348,14 @@
if (write_ptr_modem) {
write_ptr_modem->length = total_recd;
*in_busy_ptr = 1;
- diag_device_write(buf, smd_info->peripheral, write_ptr_modem);
+ err = diag_device_write(buf, smd_info->peripheral,
+ write_ptr_modem);
+ if (err) {
+ /* Free up the buffer for future use */
+ *in_busy_ptr = 0;
+ pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
+ __func__, err);
+ }
}
return 0;
@@ -356,7 +376,8 @@
if (!smd_info->in_busy_1)
buf = smd_info->buf_in_1;
- else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
+ else if (!smd_info->in_busy_2 &&
+ (smd_info->type == SMD_DATA_TYPE))
buf = smd_info->buf_in_2;
if (smd_info->ch && buf) {
@@ -526,12 +547,20 @@
} else
return -EINVAL;
} else if (driver->logging_mode == NO_LOGGING_MODE) {
- if ((data_type >= 0) && (data_type < NUM_SMD_DATA_CHANNELS)) {
+ if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
driver->smd_data[data_type].in_busy_1 = 0;
driver->smd_data[data_type].in_busy_2 = 0;
queue_work(driver->diag_wq,
&(driver->smd_data[data_type].
diag_read_smd_work));
+ if (data_type == MODEM_DATA &&
+ driver->separate_cmdrsp[data_type]) {
+ driver->smd_cmd[data_type].in_busy_1 = 0;
+ driver->smd_cmd[data_type].in_busy_2 = 0;
+ queue_work(driver->diag_wq,
+ &(driver->smd_cmd[data_type].
+ diag_read_smd_work));
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
else if (data_type == SDIO_DATA) {
@@ -564,8 +593,8 @@
driver->write_ptr_svc);
} else
err = -1;
- } else if ((data_type >= 0) &&
- (data_type < NUM_SMD_DATA_CHANNELS)) {
+ } else if ((data_type >= MODEM_DATA) &&
+ (data_type <= WCNSS_DATA)) {
write_ptr->buf = buf;
#ifdef DIAG_DEBUG
printk(KERN_INFO "writing data to USB,"
@@ -701,21 +730,30 @@
} else {
if (len > 0) {
if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
+ struct diag_smd_info *smd_info;
int index = entry.client_id;
- if (driver->smd_data[index].ch) {
- if ((index == MODEM_DATA) &&
- diag_check_mode_reset(buf)) {
- return;
- }
- mutex_lock(&driver->smd_data[index].
- smd_ch_mutex);
- smd_write(driver->smd_data[index].ch,
- buf, len);
- mutex_unlock(&driver->smd_data[index].
- smd_ch_mutex);
+ /*
+ * Mode reset should work even if
+ * modem is down
+ */
+ if ((index == MODEM_DATA) &&
+ diag_check_mode_reset(buf)) {
+ return;
+ }
+ smd_info = (driver->separate_cmdrsp[index] &&
+ index < NUM_SMD_CMD_CHANNELS) ?
+ &driver->smd_cmd[index] :
+ &driver->smd_data[index];
+
+ if (smd_info->ch) {
+ mutex_lock(&smd_info->smd_ch_mutex);
+ smd_write(smd_info->ch, buf, len);
+ mutex_unlock(&smd_info->smd_ch_mutex);
} else {
- pr_err("diag: In %s, smd channel %d not open\n",
- __func__, index);
+ pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
+ __func__, index,
+ smd_info->peripheral,
+ smd_info->type);
}
} else {
pr_alert("diag: In %s, incorrect channel: %d",
@@ -1284,9 +1322,37 @@
mutex_unlock(&driver->diag_hdlc_mutex);
}
+void diag_reset_smd_data(int queue)
+{
+ int i;
+
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ if (queue)
+ /* Poll SMD data channels to check for data */
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].diag_read_smd_work));
+ }
+
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ driver->smd_cmd[i].in_busy_1 = 0;
+ driver->smd_cmd[i].in_busy_2 = 0;
+ if (queue)
+ /* Poll SMD data channels to check for data */
+ queue_work(driver->diag_wq,
+ &(driver->smd_cmd[i].
+ diag_read_smd_work));
+ }
+ }
+}
+
#ifdef CONFIG_DIAG_OVER_USB
/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
#define N_LEGACY_WRITE (driver->poolsize + 6)
+/* Additionally support number of command data and dci channels */
+#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
#define N_LEGACY_READ 1
static void diag_usb_connect_work_fn(struct work_struct *w)
@@ -1305,18 +1371,16 @@
int i;
printk(KERN_DEBUG "diag: USB connected\n");
- err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
+ err = usb_diag_alloc_req(driver->legacy_ch,
+ (driver->supports_separate_cmdrsp ?
+ N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
N_LEGACY_READ);
if (err)
printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
driver->usb_connected = 1;
+ diag_reset_smd_data(RESET_AND_QUEUE);
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD data channels to check for data */
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].diag_read_smd_work));
/* Poll SMD CNTL channels to check for data */
diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
}
@@ -1347,6 +1411,13 @@
driver->smd_data[i].in_busy_1 = 1;
driver->smd_data[i].in_busy_2 = 1;
}
+
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ driver->smd_cmd[i].in_busy_1 = 1;
+ driver->smd_cmd[i].in_busy_2 = 1;
+ }
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1357,30 +1428,44 @@
return 0;
}
-int diagfwd_write_complete(struct diag_request *diag_write_ptr)
+static int diagfwd_check_buf_match(int num_channels,
+ struct diag_smd_info *data, unsigned char *buf)
{
- unsigned char *buf = diag_write_ptr->buf;
- int found_it = 0;
int i;
+ int found_it = 0;
- /* Determine if the write complete is for data from modem/apps/q6 */
- /* Need a context variable here instead */
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- struct diag_smd_info *data = &(driver->smd_data[i]);
- if (buf == (void *)data->buf_in_1) {
- data->in_busy_1 = 0;
+ for (i = 0; i < num_channels; i++) {
+ if (buf == (void *)data[i].buf_in_1) {
+ data[i].in_busy_1 = 0;
queue_work(driver->diag_wq,
- &(data->diag_read_smd_work));
+ &(data[i].diag_read_smd_work));
found_it = 1;
break;
- } else if (buf == (void *)data->buf_in_2) {
- data->in_busy_2 = 0;
+ } else if (buf == (void *)data[i].buf_in_2) {
+ data[i].in_busy_2 = 0;
queue_work(driver->diag_wq,
- &(data->diag_read_smd_work));
+ &(data[i].diag_read_smd_work));
found_it = 1;
break;
}
}
+
+ return found_it;
+}
+
+int diagfwd_write_complete(struct diag_request *diag_write_ptr)
+{
+ unsigned char *buf = diag_write_ptr->buf;
+ int found_it = 0;
+
+ /* Determine if the write complete is for data from modem/apps/q6 */
+ found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
+ driver->smd_data, buf);
+
+ if (!found_it && driver->supports_separate_cmdrsp)
+ found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
+ driver->smd_cmd, buf);
+
#ifdef CONFIG_DIAG_SDIO_PIPE
if (!found_it) {
if (buf == (void *)driver->buf_in_sdio) {
@@ -1528,7 +1613,8 @@
wake_up(&driver->smd_wait_q);
- if (smd_info->type == SMD_DCI_TYPE)
+ if (smd_info->type == SMD_DCI_TYPE ||
+ smd_info->type == SMD_DCI_CMD_TYPE)
queue_work(driver->diag_dci_wq,
&(smd_info->diag_read_smd_work));
else
@@ -1539,40 +1625,66 @@
{
int r = 0;
int index = -1;
+ const char *channel_name = NULL;
if (pdev->id == SMD_APPS_MODEM) {
index = MODEM_DATA;
- r = smd_open("DIAG", &driver->smd_data[index].ch,
- &driver->smd_data[index],
- diag_smd_notify);
- driver->smd_data[index].ch_save =
- driver->smd_data[index].ch;
+ channel_name = "DIAG";
}
#if defined(CONFIG_MSM_N_WAY_SMD)
- if (pdev->id == SMD_APPS_QDSP) {
+ else if (pdev->id == SMD_APPS_QDSP) {
index = LPASS_DATA;
- r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
- &driver->smd_data[index].ch,
- &driver->smd_data[index],
- diag_smd_notify);
- driver->smd_data[index].ch_save =
- driver->smd_data[index].ch;
+ channel_name = "DIAG";
}
#endif
- if (pdev->id == SMD_APPS_WCNSS) {
+ else if (pdev->id == SMD_APPS_WCNSS) {
index = WCNSS_DATA;
- r = smd_named_open_on_edge("APPS_RIVA_DATA",
- SMD_APPS_WCNSS,
+ channel_name = "APPS_RIVA_DATA";
+ }
+
+ if (index != -1) {
+ r = smd_named_open_on_edge(channel_name,
+ pdev->id,
&driver->smd_data[index].ch,
&driver->smd_data[index],
diag_smd_notify);
- driver->smd_data[index].ch_save =
- driver->smd_data[index].ch;
+ driver->smd_data[index].ch_save = driver->smd_data[index].ch;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
+ pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
+ __func__, pdev->id, r);
+
+ return 0;
+}
+
+static int diag_smd_cmd_probe(struct platform_device *pdev)
+{
+ int r = 0;
+ int index = -1;
+ const char *channel_name = NULL;
+
+ if (!driver->supports_separate_cmdrsp)
+ return 0;
+
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ channel_name = "DIAG_CMD";
+ }
+
+ if (index != -1) {
+ r = smd_named_open_on_edge(channel_name,
+ pdev->id,
+ &driver->smd_cmd[index].ch,
+ &driver->smd_cmd[index],
+ diag_smd_notify);
+ driver->smd_cmd[index].ch_save =
+ driver->smd_cmd[index].ch;
+ }
+
+ pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
+ __func__, pdev->id, r);
return 0;
}
@@ -1614,6 +1726,24 @@
},
};
+static struct platform_driver
+ smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
+ {
+ /* Modem data */
+ .probe = diag_smd_cmd_probe,
+ .driver = {
+ .name = "DIAG_CMD",
+ .owner = THIS_MODULE,
+ .pm = &diag_smd_dev_pm_ops,
+ },
+ }
+};
+
+int device_supports_separate_cmdrsp(void)
+{
+ return driver->use_device_tree;
+}
+
void diag_smd_destructor(struct diag_smd_info *smd_info)
{
if (smd_info->type == SMD_DATA_TYPE)
@@ -1699,16 +1829,22 @@
* information to the update function.
*/
smd_info->notify_context = 0;
- if (type == SMD_DATA_TYPE)
+ switch (type) {
+ case SMD_DATA_TYPE:
+ case SMD_CMD_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
- diag_clean_reg_fn);
- else if (type == SMD_CNTL_TYPE)
+ diag_clean_reg_fn);
+ break;
+ case SMD_CNTL_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
- diag_mask_update_fn);
- else if (type == SMD_DCI_TYPE)
+ diag_mask_update_fn);
+ break;
+ case SMD_DCI_TYPE:
+ case SMD_DCI_CMD_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
- diag_update_smd_dci_work_fn);
- else {
+ diag_update_smd_dci_work_fn);
+ break;
+ default:
pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
goto err;
}
@@ -1717,15 +1853,21 @@
* Set function ptr for function to call to process the data that
* was just read from the smd channel
*/
- if (type == SMD_DATA_TYPE)
+ switch (type) {
+ case SMD_DATA_TYPE:
+ case SMD_CMD_TYPE:
smd_info->process_smd_read_data = diag_process_smd_read_data;
- else if (type == SMD_CNTL_TYPE)
+ break;
+ case SMD_CNTL_TYPE:
smd_info->process_smd_read_data =
diag_process_smd_cntl_read_data;
- else if (type == SMD_DCI_TYPE)
+ break;
+ case SMD_DCI_TYPE:
+ case SMD_DCI_CMD_TYPE:
smd_info->process_smd_read_data =
diag_process_smd_dci_read_data;
- else {
+ break;
+ default:
pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
goto err;
}
@@ -1781,23 +1923,28 @@
*/
driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
driver->poolsize_hdlc : buf_tbl_size;
+ driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
- success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
- MODEM_DATA, SMD_DATA_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ driver->separate_cmdrsp[i] = 0;
- success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
- LPASS_DATA, SMD_DATA_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_data[i], i,
+ SMD_DATA_TYPE);
+ if (!success)
+ goto err;
+ }
- success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
- WCNSS_DATA, SMD_DATA_TYPE);
- if (!success)
- goto err;
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_cmd[i], i,
+ SMD_CMD_TYPE);
+ if (!success)
+ goto err;
+ }
+ }
if (driver->usb_buf_out == NULL &&
(driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
@@ -1867,6 +2014,12 @@
#endif
platform_driver_register(&msm_smd_ch1_driver);
platform_driver_register(&diag_smd_lite_driver);
+
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
+ platform_driver_register(&smd_lite_data_cmd_drivers[i]);
+ }
+
return;
err:
pr_err("diag: Could not initialize diag buffers");
@@ -1874,6 +2027,9 @@
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
diag_smd_destructor(&driver->smd_data[i]);
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_cmd[i]);
+
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -1903,9 +2059,16 @@
usb_diag_close(driver->legacy_ch);
#endif
platform_driver_unregister(&msm_smd_ch1_driver);
- platform_driver_unregister(&msm_diag_dci_driver);
platform_driver_unregister(&diag_smd_lite_driver);
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ diag_smd_destructor(&driver->smd_cmd[i]);
+ platform_driver_unregister(
+ &smd_lite_data_cmd_drivers[i]);
+ }
+ }
+
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 09f2f5e..c6e1273 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -16,6 +16,9 @@
#define NO_PROCESS 0
#define NON_APPS_PROC -1
+#define RESET_AND_NO_QUEUE 0
+#define RESET_AND_QUEUE 1
+
#define CHK_OVERFLOW(bufStart, start, end, length) \
((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
@@ -49,6 +52,7 @@
void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
int diag_process_apps_pkt(unsigned char *buf, int len);
+void diag_reset_smd_data(int queue);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 2776c58..13cbc8f 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -45,7 +45,6 @@
int total_recd)
{
int data_len = 0, type = -1, count_bytes = 0, j, flag = 0;
- int feature_mask_len;
struct bindpkt_params_per_process *pkt_params =
kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
struct diag_ctrl_msg *msg;
@@ -88,7 +87,7 @@
pkt_params->count = msg->count_entries;
pkt_params->params = kzalloc(pkt_params->count *
sizeof(struct bindpkt_params), GFP_KERNEL);
- if (pkt_params->params == NULL) {
+ if (ZERO_OR_NULL_PTR(pkt_params->params)) {
pr_alert("diag: In %s, Memory alloc fail\n",
__func__);
kfree(pkt_params);
@@ -116,11 +115,32 @@
pr_err("diag: drop reg proc %d\n",
smd_info->peripheral);
kfree(pkt_params->params);
- } else if ((type == DIAG_CTRL_MSG_FEATURE) &&
- (smd_info->peripheral == MODEM_DATA)) {
- feature_mask_len = *(int *)(buf + 8);
- driver->log_on_demand_support = (*(uint8_t *)
- (buf + 12)) & 0x04;
+ } else if (type == DIAG_CTRL_MSG_FEATURE &&
+ total_recd >= count_bytes) {
+ uint8_t feature_mask = 0;
+ int feature_mask_len = *(int *)(buf+8);
+ if (feature_mask_len > 0) {
+ feature_mask = *(uint8_t *)(buf+12);
+ if (smd_info->peripheral == MODEM_DATA)
+ driver->log_on_demand_support =
+ feature_mask &
+ F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+ /*
+ * If apps supports separate cmd/rsp channels
+ * and the peripheral supports separate cmd/rsp
+ * channels
+ */
+ if (driver->supports_separate_cmdrsp &&
+ (feature_mask & F_DIAG_REQ_RSP_CHANNEL))
+ driver->separate_cmdrsp
+ [smd_info->peripheral] =
+ ENABLE_SEPARATE_CMDRSP;
+ else
+ driver->separate_cmdrsp
+ [smd_info->peripheral] =
+ DISABLE_SEPARATE_CMDRSP;
+ }
+ flag = 1;
} else if (type != DIAG_CTRL_MSG_REG) {
flag = 1;
}
@@ -212,39 +232,38 @@
{
int r = 0;
int index = -1;
+ const char *channel_name = NULL;
/* open control ports only on 8960 & newer targets */
if (chk_apps_only()) {
if (pdev->id == SMD_APPS_MODEM) {
index = MODEM_DATA;
- r = smd_open("DIAG_CNTL",
- &driver->smd_cntl[index].ch,
- &driver->smd_cntl[index],
- diag_smd_notify);
- driver->smd_cntl[index].ch_save =
- driver->smd_cntl[index].ch;
- } else if (pdev->id == SMD_APPS_QDSP) {
+ channel_name = "DIAG_CNTL";
+ }
+#if defined(CONFIG_MSM_N_WAY_SMD)
+ else if (pdev->id == SMD_APPS_QDSP) {
index = LPASS_DATA;
- r = smd_named_open_on_edge("DIAG_CNTL",
- SMD_APPS_QDSP,
- &driver->smd_cntl[index].ch,
- &driver->smd_cntl[index],
- diag_smd_notify);
- driver->smd_cntl[index].ch_save =
- driver->smd_cntl[index].ch;
- } else if (pdev->id == SMD_APPS_WCNSS) {
+ channel_name = "DIAG_CNTL";
+ }
+#endif
+ else if (pdev->id == SMD_APPS_WCNSS) {
index = WCNSS_DATA;
- r = smd_named_open_on_edge("APPS_RIVA_CTRL",
- SMD_APPS_WCNSS,
- &driver->smd_cntl[index].ch,
- &driver->smd_cntl[index],
- diag_smd_notify);
- driver->smd_cntl[index].ch_save =
- driver->smd_cntl[index].ch;
+ channel_name = "APPS_RIVA_CTRL";
}
- pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
+ if (index != -1) {
+ r = smd_named_open_on_edge(channel_name,
+ pdev->id,
+ &driver->smd_cntl[index].ch,
+ &driver->smd_cntl[index],
+ diag_smd_notify);
+ driver->smd_cntl[index].ch_save =
+ driver->smd_cntl[index].ch;
+ }
+ pr_debug("diag: In %s, open SMD CNTL port, Id = %d, r = %d\n",
+ __func__, pdev->id, r);
}
+
return 0;
}
@@ -269,20 +288,20 @@
.probe = diag_smd_cntl_probe,
.driver = {
- .name = "DIAG_CNTL",
- .owner = THIS_MODULE,
- .pm = &diagfwd_cntl_dev_pm_ops,
- },
+ .name = "DIAG_CNTL",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_cntl_dev_pm_ops,
+ },
};
static struct platform_driver diag_smd_lite_cntl_driver = {
.probe = diag_smd_cntl_probe,
.driver = {
- .name = "APPS_RIVA_CTRL",
- .owner = THIS_MODULE,
- .pm = &diagfwd_cntl_dev_pm_ops,
- },
+ .name = "APPS_RIVA_CTRL",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_cntl_dev_pm_ops,
+ },
};
void diagfwd_cntl_init(void)
@@ -295,20 +314,12 @@
driver->log_on_demand_support = 1;
driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
- success = diag_smd_constructor(&driver->smd_cntl[MODEM_DATA],
- MODEM_DATA, SMD_CNTL_TYPE);
- if (!success)
- goto err;
-
- success = diag_smd_constructor(&driver->smd_cntl[LPASS_DATA],
- LPASS_DATA, SMD_CNTL_TYPE);
- if (!success)
- goto err;
-
- success = diag_smd_constructor(&driver->smd_cntl[WCNSS_DATA],
- WCNSS_DATA, SMD_CNTL_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_cntl[i], i,
+ SMD_CNTL_TYPE);
+ if (!success)
+ goto err;
+ }
platform_driver_register(&msm_smd_ch1_cntl_driver);
platform_driver_register(&diag_smd_lite_cntl_driver);
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index f58ab24..02b9757 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -37,7 +37,17 @@
#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID
/* Denotes that we support sending/receiving the feature mask */
-#define F_DIAG_INT_FEATURE_MASK 0x01
+#define F_DIAG_INT_FEATURE_MASK 0x01
+/* Denotes that we support responding to "Log on Demand" */
+#define F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER 0x04
+/*
+ * Supports dedicated main request/response on
+ * new Data Rx and DCI Rx channels
+ */
+#define F_DIAG_REQ_RSP_CHANNEL 0x10
+
+#define ENABLE_SEPARATE_CMDRSP 1
+#define DISABLE_SEPARATE_CMDRSP 0
struct cmd_code_range {
uint16_t cmd_code_lo;
@@ -110,6 +120,7 @@
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
+void diag_notify_ctrl_update_fn(struct work_struct *work);
void diag_clean_reg_fn(struct work_struct *work);
int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd);
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 9a43ea4..156a2a5 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -351,6 +351,7 @@
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
return 4;
case MDP_Y_CBCR_H2V2:
@@ -407,6 +408,7 @@
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
case MDP_RGB_888:
case MDP_RGB_565:
case MDP_BGR_565:
@@ -811,6 +813,7 @@
break;
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
CLR_R, 8),
MSM_ROTATOR_SRC_UNPACK_PATTERN1);
@@ -1118,6 +1121,7 @@
case MDP_XRGB_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
case MDP_YCBCR_H1V1:
case MDP_YCRCB_H1V1:
rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
@@ -1275,6 +1279,7 @@
case MDP_XRGB_8888:
case MDP_RGBX_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
is_rgb = 1;
info.dst.format = info.src.format;
break;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 79f7174..fda64e5 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -112,7 +112,7 @@
static unsigned int dbs_enable; /* number of CPUs using this policy */
/*
- * dbs_mutex protects dbs_enable in governor start/stop.
+ * dbs_mutex protects dbs_enable and dbs_info during start/stop.
*/
static DEFINE_MUTEX(dbs_mutex);
@@ -585,6 +585,10 @@
POWERSAVE_BIAS_MINLEVEL));
dbs_tuners_ins.powersave_bias = input;
+
+ mutex_lock(&dbs_mutex);
+ get_online_cpus();
+
if (!bypass) {
if (reenable_timer) {
/* reinstate dbs timer */
@@ -652,6 +656,9 @@
}
}
+ put_online_cpus();
+ mutex_unlock(&dbs_mutex);
+
return count;
}
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index af53543..5051a3a 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, 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
@@ -42,7 +42,7 @@
struct ota_dev_control;
struct ota_async_req {
- struct list_head list;
+ struct list_head rlist;
struct completion complete;
int err;
enum qce_ota_oper_enum op;
@@ -52,7 +52,7 @@
struct qce_f8_multi_pkt_req f8_mp_req;
} req;
- struct ota_dev_control *podev;
+ struct ota_qce_dev *pqce;
};
/*
@@ -68,19 +68,29 @@
/* misc device */
struct miscdevice miscdevice;
+ struct list_head ready_commands;
+ unsigned magic;
+ struct list_head qce_dev;
+ spinlock_t lock;
+ struct mutex register_lock;
+ bool registered;
+ uint32_t total_units;
+};
+struct ota_qce_dev {
+ struct list_head qlist;
/* qce handle */
void *qce;
/* platform device */
struct platform_device *pdev;
- unsigned magic;
-
- struct list_head ready_commands;
struct ota_async_req *active_command;
- spinlock_t lock;
struct tasklet_struct done_tasklet;
+ struct ota_dev_control *podev;
+ uint32_t unit;
+ u32 totalReq;
+ u32 errReq;
};
#define OTA_MAGIC 0x4f544143
@@ -89,7 +99,7 @@
unsigned cmd, unsigned long arg);
static int qcota_open(struct inode *inode, struct file *file);
static int qcota_release(struct inode *inode, struct file *file);
-static int start_req(struct ota_dev_control *podev);
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq);
static const struct file_operations qcota_fops = {
.owner = THIS_MODULE,
@@ -98,35 +108,15 @@
.release = qcota_release,
};
-static struct ota_dev_control qcota_dev[] = {
- {
- .miscdevice = {
+static struct ota_dev_control qcota_dev = {
+ .miscdevice = {
.minor = MISC_DYNAMIC_MINOR,
.name = "qcota0",
.fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
},
- {
- .miscdevice = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "qcota1",
- .fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
- },
- {
- .miscdevice = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "qcota2",
- .fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
- }
+ .magic = OTA_MAGIC,
};
-#define MAX_OTA_DEVICE ARRAY_SIZE(qcota_dev)
-
#define DEBUG_MAX_FNAME 16
#define DEBUG_MAX_RW_BUF 1024
@@ -141,27 +131,22 @@
u32 f9_op_success;
u32 f9_op_fail;
};
-static struct qcota_stat _qcota_stat[MAX_OTA_DEVICE];
+static struct qcota_stat _qcota_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcota[MAX_OTA_DEVICE];
+static int _debug_qcota;
-static struct ota_dev_control *qcota_minor_to_control(unsigned n)
+static struct ota_dev_control *qcota_control(void)
{
- int i;
- for (i = 0; i < MAX_OTA_DEVICE; i++) {
- if (qcota_dev[i].miscdevice.minor == n)
- return &qcota_dev[i];
- }
- return NULL;
+ return &qcota_dev;
}
static int qcota_open(struct inode *inode, struct file *file)
{
struct ota_dev_control *podev;
- podev = qcota_minor_to_control(MINOR(inode->i_rdev));
+ podev = qcota_control();
if (podev == NULL) {
pr_err("%s: no such device %d\n", __func__,
MINOR(inode->i_rdev));
@@ -191,38 +176,52 @@
static void req_done(unsigned long data)
{
- struct ota_dev_control *podev = (struct ota_dev_control *)data;
+ struct ota_qce_dev *pqce = (struct ota_qce_dev *)data;
+ struct ota_dev_control *podev = pqce->podev;
struct ota_async_req *areq;
unsigned long flags;
struct ota_async_req *new_req = NULL;
int ret = 0;
+
spin_lock_irqsave(&podev->lock, flags);
- areq = podev->active_command;
- podev->active_command = NULL;
+
+ areq = pqce->active_command;
+ if (unlikely(areq == NULL))
+ pr_err("ota_crypto: req_done, no active request\n");
+ pqce->active_command = NULL;
again:
if (!list_empty(&podev->ready_commands)) {
new_req = container_of(podev->ready_commands.next,
- struct ota_async_req, list);
- list_del(&new_req->list);
- podev->active_command = new_req;
+ struct ota_async_req, rlist);
+ list_del(&new_req->rlist);
+ pqce->active_command = new_req;
+ spin_unlock_irqrestore(&podev->lock, flags);
+
new_req->err = 0;
- ret = start_req(podev);
- }
+ ret = start_req(pqce, new_req); /* start a new request */
- spin_unlock_irqrestore(&podev->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&podev->lock, flags);
+ };
- if (areq)
+ if (areq) {
complete(&areq->complete);
-
- if (new_req && ret) {
- complete(&new_req->complete);
- spin_lock_irqsave(&podev->lock, flags);
- podev->active_command = NULL;
areq = NULL;
+ };
+
+ /* if error from issuing request */
+ if (unlikely(new_req && ret)) {
+ new_req->err = ret;
+ complete(&new_req->complete);
ret = 0;
new_req = NULL;
+
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce->active_command = NULL;
+
+ /* try to get next new request */
goto again;
}
@@ -233,64 +232,61 @@
int ret)
{
struct ota_async_req *areq = (struct ota_async_req *) cookie;
- struct ota_dev_control *podev;
- struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
- podev = areq->podev;
- pstat = &_qcota_stat[podev->pdev->id];
+ pqce = areq->pqce;
areq->req.f9_req.mac_i = (uint32_t) icv;
- if (ret)
+ if (ret) {
+ pqce->errReq++;
areq->err = -ENXIO;
- else
+ } else
areq->err = 0;
- tasklet_schedule(&podev->done_tasklet);
-};
+ tasklet_schedule(&pqce->done_tasklet);
+}
static void f8_cb(void *cookie, unsigned char *icv, unsigned char *iv,
int ret)
{
struct ota_async_req *areq = (struct ota_async_req *) cookie;
- struct ota_dev_control *podev;
- struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
- podev = areq->podev;
- pstat = &_qcota_stat[podev->pdev->id];
+ pqce = areq->pqce;
- if (ret)
+ if (ret) {
+ pqce->errReq++;
areq->err = -ENXIO;
- else
+ } else {
areq->err = 0;
+ }
- tasklet_schedule(&podev->done_tasklet);
-};
+ tasklet_schedule(&pqce->done_tasklet);
+}
-static int start_req(struct ota_dev_control *podev)
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq)
{
- struct ota_async_req *areq;
struct qce_f9_req *pf9;
struct qce_f8_multi_pkt_req *p_mp_f8;
struct qce_f8_req *pf8;
int ret = 0;
- /* start the command on the podev->active_command */
- areq = podev->active_command;
- areq->podev = podev;
+ /* command should be on the podev->active_command */
+ areq->pqce = pqce;
switch (areq->op) {
case QCE_OTA_F8_OPER:
pf8 = &areq->req.f8_req;
- ret = qce_f8_req(podev->qce, pf8, areq, f8_cb);
+ ret = qce_f8_req(pqce->qce, pf8, areq, f8_cb);
break;
case QCE_OTA_MPKT_F8_OPER:
p_mp_f8 = &areq->req.f8_mp_req;
- ret = qce_f8_multi_pkt_req(podev->qce, p_mp_f8, areq, f8_cb);
+ ret = qce_f8_multi_pkt_req(pqce->qce, p_mp_f8, areq, f8_cb);
break;
case QCE_OTA_F9_OPER:
pf9 = &areq->req.f9_req;
- ret = qce_f9_req(podev->qce, pf9, areq, f9_cb);
+ ret = qce_f9_req(pqce->qce, pf9, areq, f9_cb);
break;
default:
@@ -298,32 +294,60 @@
break;
};
areq->err = ret;
+ pqce->totalReq++;
+ if (ret)
+ pqce->errReq++;
return ret;
-};
+}
+
+static struct ota_qce_dev *schedule_qce(struct ota_dev_control *podev)
+{
+ /* do this function with spinlock set */
+ struct ota_qce_dev *p;
+
+ if (unlikely(list_empty(&podev->qce_dev))) {
+ pr_err("%s: no valid qce to schedule\n", __func__);
+ return NULL;
+ }
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ if (p->active_command == NULL)
+ return p;
+ }
+ return NULL;
+}
static int submit_req(struct ota_async_req *areq, struct ota_dev_control *podev)
{
unsigned long flags;
int ret = 0;
struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
areq->err = 0;
- spin_lock_irqsave(&podev->lock, flags);
- if (podev->active_command == NULL) {
- podev->active_command = areq;
- ret = start_req(podev);
- } else {
- list_add_tail(&areq->list, &podev->ready_commands);
- }
- if (ret != 0)
- podev->active_command = NULL;
- spin_unlock_irqrestore(&podev->lock, flags);
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce = schedule_qce(podev);
+ if (pqce) {
+ pqce->active_command = areq;
+ spin_unlock_irqrestore(&podev->lock, flags);
+
+ ret = start_req(pqce, areq);
+ if (ret != 0) {
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce->active_command = NULL;
+ spin_unlock_irqrestore(&podev->lock, flags);
+ }
+
+ } else {
+ list_add_tail(&areq->rlist, &podev->ready_commands);
+ spin_unlock_irqrestore(&podev->lock, flags);
+ }
if (ret == 0)
wait_for_completion(&areq->complete);
- pstat = &_qcota_stat[podev->pdev->id];
+ pstat = &_qcota_stat;
switch (areq->op) {
case QCE_OTA_F8_OPER:
if (areq->err)
@@ -350,7 +374,7 @@
};
return areq->err;
-};
+}
static long qcota_ioctl(struct file *file,
unsigned cmd, unsigned long arg)
@@ -377,7 +401,7 @@
init_completion(&areq.complete);
- pstat = &_qcota_stat[podev->pdev->id];
+ pstat = &_qcota_stat;
switch (cmd) {
case QCOTA_F9_REQ:
@@ -523,67 +547,112 @@
int rc = 0;
struct ota_dev_control *podev;
struct ce_hw_support ce_support;
+ struct ota_qce_dev *pqce;
+ unsigned long flags;
- if (pdev->id >= MAX_OTA_DEVICE) {
- pr_err("%s: device id %d exceeds allowed %d\n",
- __func__, pdev->id, MAX_OTA_DEVICE);
- return -ENOENT;
+ podev = &qcota_dev;
+ pqce = kzalloc(sizeof(*pqce), GFP_KERNEL);
+ if (!pqce) {
+ pr_err("qcota_probe: Memory allocation FAIL\n");
+ return -ENOMEM;
}
- podev = &qcota_dev[pdev->id];
-
- INIT_LIST_HEAD(&podev->ready_commands);
- podev->active_command = NULL;
- spin_lock_init(&podev->lock);
- tasklet_init(&podev->done_tasklet, req_done, (unsigned long)podev);
+ pqce->podev = podev;
+ pqce->active_command = NULL;
+ tasklet_init(&pqce->done_tasklet, req_done, (unsigned long)pqce);
/* open qce */
handle = qce_open(pdev, &rc);
if (handle == NULL) {
- pr_err("%s: device id %d, can not open qce\n",
- __func__, pdev->id);
- platform_set_drvdata(pdev, NULL);
- return rc;
+ pr_err("%s: device %s, can not open qce\n",
+ __func__, pdev->name);
+ goto err;
}
if (qce_hw_support(handle, &ce_support) < 0 ||
ce_support.ota == false) {
- pr_err("%s: device id %d, qce does not support ota capability\n",
- __func__, pdev->id);
+ pr_err("%s: device %s, qce does not support ota capability\n",
+ __func__, pdev->name);
rc = -ENODEV;
goto err;
}
- podev->qce = handle;
- podev->pdev = pdev;
- platform_set_drvdata(pdev, podev);
+ pqce->qce = handle;
+ pqce->pdev = pdev;
+ pqce->totalReq = 0;
+ pqce->errReq = 0;
+ platform_set_drvdata(pdev, pqce);
- rc = misc_register(&podev->miscdevice);
- if (rc < 0)
+ mutex_lock(&podev->register_lock);
+ rc = 0;
+ if (podev->registered == false) {
+ rc = misc_register(&podev->miscdevice);
+ if (rc == 0) {
+ pqce->unit = podev->total_units;
+ podev->total_units++;
+ podev->registered = true;
+ };
+ } else {
+ pqce->unit = podev->total_units;
+ podev->total_units++;
+ }
+ mutex_unlock(&podev->register_lock);
+ if (rc) {
+ pr_err("ion: failed to register misc device.\n");
goto err;
+ }
+
+ spin_lock_irqsave(&podev->lock, flags);
+ list_add_tail(&pqce->qlist, &podev->qce_dev);
+ spin_unlock_irqrestore(&podev->lock, flags);
return 0;
err:
if (handle)
qce_close(handle);
+
platform_set_drvdata(pdev, NULL);
- podev->qce = NULL;
- podev->pdev = NULL;
+ tasklet_kill(&pqce->done_tasklet);
+ kfree(pqce);
return rc;
-};
+}
static int qcota_remove(struct platform_device *pdev)
{
struct ota_dev_control *podev;
+ struct ota_qce_dev *pqce;
+ unsigned long flags;
- podev = platform_get_drvdata(pdev);
- if (!podev)
+ pqce = platform_get_drvdata(pdev);
+ if (!pqce)
return 0;
- if (podev->qce)
- qce_close(podev->qce);
+ if (pqce->qce)
+ qce_close(pqce->qce);
- if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
- misc_deregister(&podev->miscdevice);
- tasklet_kill(&podev->done_tasklet);
+ podev = pqce->podev;
+ if (!podev)
+ goto ret;
+
+ spin_lock_irqsave(&podev->lock, flags);
+ list_del(&pqce->qlist);
+ spin_unlock_irqrestore(&podev->lock, flags);
+
+ mutex_lock(&podev->register_lock);
+ if (--podev->total_units == 0) {
+ if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
+ misc_deregister(&podev->miscdevice);
+ podev->registered = false;
+ }
+ mutex_unlock(&podev->register_lock);
+ret:
+
+ tasklet_kill(&pqce->done_tasklet);
+ kfree(pqce);
return 0;
+}
+
+static struct of_device_id qcota_match[] = {
+ { .compatible = "qcom,qcota",
+ },
+ {}
};
static struct platform_driver qcota_plat_driver = {
@@ -592,18 +661,21 @@
.driver = {
.name = "qcota",
.owner = THIS_MODULE,
+ .of_match_table = qcota_match,
},
};
-static int _disp_stats(int id)
+static int _disp_stats(void)
{
struct qcota_stat *pstat;
int len = 0;
+ struct ota_dev_control *podev = &qcota_dev;
+ unsigned long flags;
+ struct ota_qce_dev *p;
- pstat = &_qcota_stat[id];
+ pstat = &_qcota_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "\nQualcomm OTA crypto accelerator %d Statistics:\n",
- id + 1);
+ "\nQualcomm OTA crypto accelerator Statistics:\n");
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" F8 request : %d\n",
@@ -635,6 +707,27 @@
" F9 operation fail : %d\n",
pstat->f9_op_fail);
+ spin_lock_irqsave(&podev->lock, flags);
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ len += snprintf(
+ _debug_read_buf + len,
+ DEBUG_MAX_RW_BUF - len - 1,
+ " Engine %d Req : %d\n",
+ p->unit,
+ p->totalReq
+ );
+ len += snprintf(
+ _debug_read_buf + len,
+ DEBUG_MAX_RW_BUF - len - 1,
+ " Engine %d Req Error : %d\n",
+ p->unit,
+ p->errReq
+ );
+ }
+
+ spin_unlock_irqrestore(&podev->lock, flags);
+
return len;
}
@@ -648,10 +741,9 @@
size_t count, loff_t *ppos)
{
int rc = -EINVAL;
- int qcota = *((int *) file->private_data);
int len;
- len = _disp_stats(qcota);
+ len = _disp_stats();
rc = simple_read_from_buffer((void __user *) buf, len,
ppos, (void *) _debug_read_buf, len);
@@ -662,12 +754,23 @@
static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct ota_dev_control *podev = &qcota_dev;
+ unsigned long flags;
+ struct ota_qce_dev *p;
- int qcota = *((int *) file->private_data);
+ memset((char *)&_qcota_stat, 0, sizeof(struct qcota_stat));
- memset((char *)&_qcota_stat[qcota], 0, sizeof(struct qcota_stat));
+ spin_lock_irqsave(&podev->lock, flags);
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ p->totalReq = 0;
+ p->errReq = 0;
+ }
+
+ spin_unlock_irqrestore(&podev->lock, flags);
+
return count;
-};
+}
static const struct file_operations _debug_stats_ops = {
.open = _debug_stats_open,
@@ -679,7 +782,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcota", NULL);
@@ -689,17 +791,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_OTA_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcota[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcota[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcota debugfs_create_file fail, error %ld\n",
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-0");
+ _debug_qcota = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcota, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcota debugfs_create_file fail, error %ld\n",
PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
@@ -710,10 +810,20 @@
static int __init qcota_init(void)
{
int rc;
+ struct ota_dev_control *podev;
rc = _qcota_debug_init();
if (rc)
return rc;
+
+ podev = &qcota_dev;
+ INIT_LIST_HEAD(&podev->ready_commands);
+ INIT_LIST_HEAD(&podev->qce_dev);
+ spin_lock_init(&podev->lock);
+ mutex_init(&podev->register_lock);
+ podev->registered = false;
+ podev->total_units = 0;
+
return platform_driver_register(&qcota_plat_driver);
}
static void __exit qcota_exit(void)
@@ -725,7 +835,7 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rohit Vaswani <rvaswani@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Ota Crypto driver");
-MODULE_VERSION("1.01");
+MODULE_VERSION("1.02");
module_init(qcota_init);
module_exit(qcota_exit);
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index cf75e93..c14143f 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -1,6 +1,6 @@
/* Qualcomm Crypto Engine driver API
*
- * 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
@@ -116,6 +116,7 @@
bool aligned_only;
bool bam;
bool is_shared;
+ bool hw_key;
};
/* Sha operation parameters */
@@ -131,6 +132,7 @@
bool last_blk; /* last block indicator */
unsigned int size; /* data length in bytes */
void *areq;
+ unsigned int flags;
};
struct qce_req {
@@ -154,6 +156,7 @@
unsigned int cryptlen; /* data length */
unsigned int use_pmem; /* is source of data PMEM allocated? */
struct qcedev_pmem_info *pmem; /* pointer to pmem_info structure*/
+ unsigned int flags;
};
void *qce_open(struct platform_device *pdev, int *rc);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index a3a662a..bff9db5 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -33,6 +33,7 @@
#include <mach/dma.h>
#include <mach/clk.h>
#include <mach/socinfo.h>
+#include <mach/qcrypto.h>
#include "qce.h"
#include "qce50.h"
@@ -63,6 +64,7 @@
int memsize; /* Memory allocated */
int is_shared; /* CE HW is shared */
bool support_cmd_dscr;
+ bool support_hw_key;
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
@@ -458,31 +460,25 @@
else
key_size = creq->encklen;
- _byte_stream_to_net_words(enckey32, creq->enckey, key_size);
pce = cmdlistinfo->go_proc;
-
- /* check for null key. If null, use hw key*/
- enck_size_in_word = key_size/sizeof(uint32_t);
- for (i = 0; i < enck_size_in_word; i++) {
- if (enckey32[i] != 0)
- break;
- }
- if (i == enck_size_in_word) {
+ if ((creq->flags & QCRYPTO_CTX_USE_HW_KEY) == QCRYPTO_CTX_USE_HW_KEY) {
use_hw_key = true;
- pce->addr = (uint32_t)(CRYPTO_GOPROC_QC_KEY_REG +
- pce_dev->phy_iobase);
- }
- if (use_hw_key == false) {
- for (i = 0; i < enck_size_in_word; i++) {
- if (enckey32[i] != 0xFFFFFFFF)
- break;
- }
- if (i == enck_size_in_word)
+ } else {
+ if ((creq->flags & QCRYPTO_CTX_USE_PIPE_KEY) ==
+ QCRYPTO_CTX_USE_PIPE_KEY)
use_pipe_key = true;
}
- if (use_hw_key == false)
+ pce = cmdlistinfo->go_proc;
+ if (use_hw_key == true)
+ pce->addr = (uint32_t)(CRYPTO_GOPROC_QC_KEY_REG +
+ pce_dev->phy_iobase);
+ else
pce->addr = (uint32_t)(CRYPTO_GOPROC_REG +
pce_dev->phy_iobase);
+ if ((use_pipe_key == false) && (use_hw_key == false)) {
+ _byte_stream_to_net_words(enckey32, creq->enckey, key_size);
+ enck_size_in_word = key_size/sizeof(uint32_t);
+ }
if ((creq->op == QCE_REQ_AEAD) && (creq->mode == QCE_MODE_CCM)) {
uint32_t authklen32 = creq->encklen/sizeof(uint32_t);
@@ -621,11 +617,12 @@
}
/* write xts du size */
pce = cmdlistinfo->encr_xts_du_size;
- if (use_pipe_key == true)
+ if (!(creq->flags & QCRYPTO_CTX_XTS_MASK))
+ pce->data = creq->cryptlen;
+ else
pce->data = min((unsigned int)QCE_SECTOR_SIZE,
creq->cryptlen);
- else
- pce->data = creq->cryptlen;
+
}
if (creq->mode != QCE_MODE_ECB) {
if (creq->mode == QCE_MODE_XTS)
@@ -917,26 +914,17 @@
else
key_size = creq->encklen;
- _byte_stream_to_net_words(enckey32, creq->enckey, key_size);
-
- /* check for null key. If null, use hw key*/
- enck_size_in_word = key_size/sizeof(uint32_t);
- for (i = 0; i < enck_size_in_word; i++) {
- if (enckey32[i] != 0)
- break;
- }
- if (i == enck_size_in_word)
+ if ((creq->flags & QCRYPTO_CTX_USE_HW_KEY) == QCRYPTO_CTX_USE_HW_KEY) {
use_hw_key = true;
-
- if (use_hw_key == false) {
- for (i = 0; i < enck_size_in_word; i++) {
- if (enckey32[i] != 0xFFFFFFFF)
- break;
- }
- if (i == enck_size_in_word)
+ } else {
+ if ((creq->flags & QCRYPTO_CTX_USE_PIPE_KEY) ==
+ QCRYPTO_CTX_USE_PIPE_KEY)
use_pipe_key = true;
}
-
+ if ((use_pipe_key == false) && (use_hw_key == false)) {
+ _byte_stream_to_net_words(enckey32, creq->enckey, key_size);
+ enck_size_in_word = key_size/sizeof(uint32_t);
+ }
if ((creq->op == QCE_REQ_AEAD) && (creq->mode == QCE_MODE_CCM)) {
uint32_t authklen32 = creq->encklen/sizeof(uint32_t);
uint32_t noncelen32 = MAX_NONCE/sizeof(uint32_t);
@@ -1858,7 +1846,7 @@
* Set flag to indicate BAM global device control is managed
* remotely.
*/
- if (pce_dev->support_cmd_dscr == false)
+ if ((pce_dev->support_cmd_dscr == false) || (pce_dev->is_shared))
bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
else
bam.manage = SPS_BAM_MGR_LOCAL;
@@ -2741,8 +2729,14 @@
pce_dev->ce_sps.ce_burst_size);
pce_dev->ce_sps.result_dump = (uint32_t)vaddr;
pce_dev->ce_sps.result = (struct ce_result_dump_format *)vaddr;
- vaddr += 128;
+ vaddr += CRYPTO_RESULT_DUMP_SIZE;
+ pce_dev->ce_sps.ignore_buffer = (uint32_t)vaddr;
+ vaddr += pce_dev->ce_sps.ce_burst_size * 2;
+
+ if ((vaddr - pce_dev->coh_vmem) > pce_dev->memsize)
+ panic("qce50: Not enough coherent memory. Allocate %x , need %x",
+ pce_dev->memsize, vaddr - pce_dev->coh_vmem);
return 0;
}
@@ -3311,6 +3305,8 @@
pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
"qcom,ce-hw-shared");
+ pce_dev->support_hw_key = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,ce-hw-key");
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -3639,6 +3635,7 @@
ce_support->ota = false;
ce_support->bam = true;
ce_support->is_shared = (pce_dev->is_shared == 1) ? true : false;
+ ce_support->hw_key = pce_dev->support_hw_key;
ce_support->aes_ccm = true;
if (pce_dev->ce_sps.minor_version)
ce_support->aligned_only = false;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index a18fb8b..d069f2e 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1937,9 +1937,10 @@
rc = misc_register(&podev->miscdevice);
qce_hw_support(podev->qce, &podev->ce_support);
if (podev->ce_support.bam) {
- podev->platform_support.ce_shared = 0;
+ podev->platform_support.ce_shared = podev->ce_support.is_shared;
podev->platform_support.shared_ce_resource = 0;
- podev->platform_support.hw_key_support = 0;
+ podev->platform_support.hw_key_support =
+ podev->ce_support.hw_key;
podev->platform_support.bus_scale_table = NULL;
podev->platform_support.sha_hmac = 1;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 375516b..39b9a46 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -39,6 +39,7 @@
#include <mach/scm.h>
#include <linux/platform_data/qcom_crypto_device.h>
#include <mach/msm_bus.h>
+#include <mach/qcrypto.h>
#include "qce.h"
@@ -217,6 +218,7 @@
unsigned int auth_key_len;
struct crypto_priv *cp;
+ unsigned int flags;
};
struct qcrypto_cipher_req_ctx {
@@ -275,6 +277,7 @@
struct scatterlist *sg;
struct scatterlist tmp_sg;
struct crypto_priv *cp;
+ unsigned int flags;
};
struct qcrypto_sha_req_ctx {
@@ -771,11 +774,21 @@
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
struct crypto_priv *cp = ctx->cp;
+ if ((ctx->flags & QCRYPTO_CTX_USE_HW_KEY) == QCRYPTO_CTX_USE_HW_KEY)
+ return 0;
+
if (_qcrypto_check_aes_keylen(cipher, cp, len)) {
return -EINVAL;
} else {
ctx->enc_key_len = len;
- memcpy(ctx->enc_key, key, len);
+ if (!(ctx->flags & QCRYPTO_CTX_USE_PIPE_KEY)) {
+ if (key != NULL) {
+ memcpy(ctx->enc_key, key, len);
+ } else {
+ pr_err("%s Inavlid key pointer\n", __func__);
+ return -EINVAL;
+ }
+ }
}
return 0;
};
@@ -787,12 +800,20 @@
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
struct crypto_priv *cp = ctx->cp;
-
+ if ((ctx->flags & QCRYPTO_CTX_USE_HW_KEY) == QCRYPTO_CTX_USE_HW_KEY)
+ return 0;
if (_qcrypto_check_aes_keylen(cipher, cp, len/2)) {
return -EINVAL;
} else {
ctx->enc_key_len = len;
- memcpy(ctx->enc_key, key, len);
+ if (!(ctx->flags & QCRYPTO_CTX_USE_PIPE_KEY)) {
+ if (key != NULL) {
+ memcpy(ctx->enc_key, key, len);
+ } else {
+ pr_err("%s Inavlid key pointer\n", __func__);
+ return -EINVAL;
+ }
+ }
}
return 0;
};
@@ -805,6 +826,12 @@
u32 tmp[DES_EXPKEY_WORDS];
int ret = des_ekey(tmp, key);
+ if ((ctx->flags & QCRYPTO_CTX_USE_HW_KEY) == QCRYPTO_CTX_USE_HW_KEY) {
+ pr_err("%s HW KEY usage not supported for DES algorithm\n",
+ __func__);
+ return 0;
+ };
+
if (len != DES_KEY_SIZE) {
crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
@@ -816,7 +843,14 @@
}
ctx->enc_key_len = len;
- memcpy(ctx->enc_key, key, len);
+ if (!(ctx->flags & QCRYPTO_CTX_USE_PIPE_KEY)) {
+ if (key != NULL) {
+ memcpy(ctx->enc_key, key, len);
+ } else {
+ pr_err("%s Inavlid key pointer\n", __func__);
+ return -EINVAL;
+ }
+ }
return 0;
};
@@ -826,12 +860,24 @@
struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ if ((ctx->flags & QCRYPTO_CTX_USE_HW_KEY) == QCRYPTO_CTX_USE_HW_KEY) {
+ pr_err("%s HW KEY usage not supported for 3DES algorithm\n",
+ __func__);
+ return 0;
+ };
if (len != DES3_EDE_KEY_SIZE) {
crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
};
ctx->enc_key_len = len;
- memcpy(ctx->enc_key, key, len);
+ if (!(ctx->flags & QCRYPTO_CTX_USE_PIPE_KEY)) {
+ if (key != NULL) {
+ memcpy(ctx->enc_key, key, len);
+ } else {
+ pr_err("%s Inavlid key pointer\n", __func__);
+ return -EINVAL;
+ }
+ }
return 0;
};
@@ -1216,6 +1262,7 @@
qreq.ivsize = crypto_ablkcipher_ivsize(tfm);
qreq.cryptlen = req->nbytes;
qreq.use_pmem = 0;
+ qreq.flags = cipher_ctx->flags;
if ((cipher_ctx->enc_key_len == 0) &&
(cp->platform_support.hw_key_support == 0))
@@ -1249,6 +1296,7 @@
sreq.last_blk = sha_ctx->last_blk;
sreq.size = req->nbytes;
sreq.areq = req;
+ sreq.flags = sha_ctx->flags;
switch (sha_ctx->alg) {
case QCE_HASH_SHA1:
@@ -1308,6 +1356,8 @@
qreq.authklen = cipher_ctx->auth_key_len;
qreq.authsize = crypto_aead_authsize(aead);
qreq.ivsize = crypto_aead_ivsize(aead);
+ qreq.flags = cipher_ctx->flags;
+
if (qreq.mode == QCE_MODE_CCM) {
if (qreq.dir == QCE_ENCRYPT)
qreq.cryptlen = req->cryptlen;
@@ -2922,6 +2972,99 @@
return _sha_digest(req);
}
+int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+
+ if ((flags & QCRYPTO_CTX_USE_HW_KEY) &&
+ (cp->platform_support.hw_key_support == false)) {
+ pr_err("%s HW key usage not supported\n", __func__);
+ return -EINVAL;
+ }
+ if (((flags | ctx->flags) & QCRYPTO_CTX_KEY_MASK) ==
+ QCRYPTO_CTX_KEY_MASK) {
+ pr_err("%s Cannot set all key flags\n", __func__);
+ return -EINVAL;
+ }
+
+ ctx->flags |= flags;
+ return 0;
+};
+EXPORT_SYMBOL(qcrypto_cipher_set_flag);
+
+int qcrypto_aead_set_flag(struct aead_request *req, unsigned int flags)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+
+ if ((flags & QCRYPTO_CTX_USE_HW_KEY) &&
+ (cp->platform_support.hw_key_support == false)) {
+ pr_err("%s HW key usage not supported\n", __func__);
+ return -EINVAL;
+ }
+ if (((flags | ctx->flags) & QCRYPTO_CTX_KEY_MASK) ==
+ QCRYPTO_CTX_KEY_MASK) {
+ pr_err("%s Cannot set all key flags\n", __func__);
+ return -EINVAL;
+ }
+
+ ctx->flags |= flags;
+ return 0;
+};
+EXPORT_SYMBOL(qcrypto_aead_set_flag);
+
+int qcrypto_ahash_set_flag(struct ahash_request *req, unsigned int flags)
+{
+ struct qcrypto_sha_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+
+ if ((flags & QCRYPTO_CTX_USE_HW_KEY) &&
+ (cp->platform_support.hw_key_support == false)) {
+ pr_err("%s HW key usage not supported\n", __func__);
+ return -EINVAL;
+ }
+ if (((flags | ctx->flags) & QCRYPTO_CTX_KEY_MASK) ==
+ QCRYPTO_CTX_KEY_MASK) {
+ pr_err("%s Cannot set all key flags\n", __func__);
+ return -EINVAL;
+ }
+
+ ctx->flags |= flags;
+ return 0;
+};
+EXPORT_SYMBOL(qcrypto_ahash_set_flag);
+
+int qcrypto_cipher_clear_flag(struct ablkcipher_request *req,
+ unsigned int flags)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+ ctx->flags &= ~flags;
+ return 0;
+
+};
+EXPORT_SYMBOL(qcrypto_cipher_clear_flag);
+
+int qcrypto_aead_clear_flag(struct aead_request *req, unsigned int flags)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+ ctx->flags &= ~flags;
+ return 0;
+
+};
+EXPORT_SYMBOL(qcrypto_aead_clear_flag);
+
+int qcrypto_ahash_clear_flag(struct ahash_request *req, unsigned int flags)
+{
+ struct qcrypto_sha_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+
+ ctx->flags &= ~flags;
+ return 0;
+};
+EXPORT_SYMBOL(qcrypto_ahash_clear_flag);
+
static struct ahash_alg _qcrypto_ahash_algos[] = {
{
.init = _sha1_init,
@@ -3387,9 +3530,9 @@
cp->pdev = pdev;
qce_hw_support(cp->qce, &cp->ce_support);
if (cp->ce_support.bam) {
- cp->platform_support.ce_shared = 0;
+ cp->platform_support.ce_shared = cp->ce_support.is_shared;
cp->platform_support.shared_ce_resource = 0;
- cp->platform_support.hw_key_support = 0;
+ cp->platform_support.hw_key_support = cp->ce_support.hw_key;
cp->platform_support.bus_scale_table = NULL;
cp->platform_support.sha_hmac = 1;
diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c
index e8b5489..495dd24 100644
--- a/drivers/gpu/ion/ion_page_pool.c
+++ b/drivers/gpu/ion/ion_page_pool.c
@@ -44,6 +44,7 @@
sg_init_table(&sg, 1);
sg_set_page(&sg, page, PAGE_SIZE << pool->order, 0);
+ sg_dma_address(&sg) = sg_phys(&sg);
dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
return page;
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index fb6dc2d..2bab7c4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -88,6 +88,7 @@
}
sg_init_table(&sg, 1);
sg_set_page(&sg, page, PAGE_SIZE << order, 0);
+ sg_dma_address(&sg) = sg_phys(&sg);
dma_sync_sg_for_device(NULL, &sg, 1, DMA_BIDIRECTIONAL);
}
if (!page)
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index 58eca24..623a174 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -13,6 +13,7 @@
*/
#include <linux/memory_alloc.h>
+#include <linux/slab.h>
#include <linux/types.h>
#include <mach/scm.h>
#include <linux/highmem.h>
@@ -97,18 +98,17 @@
nchunks = size / V2_CHUNK_SIZE;
- chunk_list = allocate_contiguous_ebi(sizeof(unsigned long)*nchunks,
- SZ_4K, 0);
+ chunk_list = kmalloc(sizeof(unsigned long)*nchunks, GFP_KERNEL);
if (!chunk_list)
return -ENOMEM;
for (i = 0; i < nchunks; i++)
chunk_list[i] = phy_base + i * V2_CHUNK_SIZE;
- ret = ion_cp_change_chunks_state(memory_pool_node_paddr(chunk_list),
+ ret = ion_cp_change_chunks_state(__pa(chunk_list),
nchunks, V2_CHUNK_SIZE, usage, lock);
- free_contiguous_memory(chunk_list);
+ kfree(chunk_list);
return ret;
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index aad2882..5ad2394 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -166,6 +166,15 @@
/* version of pfp microcode that supports sync_lock
between CPU and GPU for IOMMU-v0 programming */
unsigned int sync_lock_pfp_ver;
+ /* PM4 jump table index */
+ unsigned int pm4_jt_idx;
+ /* PM4 jump table load addr */
+ unsigned int pm4_jt_addr;
+ /* PFP jump table index */
+ unsigned int pfp_jt_idx;
+ /* PFP jump table load addr */
+ unsigned int pfp_jt_addr;
+
} adreno_gpulist[] = {
{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
@@ -202,10 +211,11 @@
512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 },
{ ADRENO_REV_A330, 3, 3, 0, ANY_ID,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_1M, NO_VER, NO_VER },
+ 512, 0, 2, SZ_1M, NO_VER, NO_VER, 0x8AD, 0x2E4, 0x201, 0x200 },
{ ADRENO_REV_A305B, 3, 0, 5, 0x10,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_128K, NO_VER, NO_VER },
+ 512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
+ 0x201, 0x200 },
{ ADRENO_REV_A305C, 3, 0, 5, 0x20,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
@@ -527,12 +537,8 @@
device->pwrctrl.irq_last = 1;
if (device->requested_state == KGSL_STATE_NONE) {
- if (device->pwrctrl.nap_allowed == true) {
- kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
- queue_work(device->work_queue, &device->idle_check_ws);
- } else if (device->pwrscale.policy != NULL) {
- queue_work(device->work_queue, &device->idle_check_ws);
- }
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+ queue_work(device->work_queue, &device->idle_check_ws);
}
/* Reset the time-out in our idle timer */
@@ -603,10 +609,10 @@
static unsigned int _adreno_iommu_setstate_v0(struct kgsl_device *device,
unsigned int *cmds_orig,
- unsigned int pt_val,
+ phys_addr_t pt_val,
int num_iommu_units, uint32_t flags)
{
- unsigned int reg_pt_val;
+ phys_addr_t reg_pt_val;
unsigned int *cmds = cmds_orig;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
@@ -632,8 +638,10 @@
* IOMMU units
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
- i, KGSL_IOMMU_CONTEXT_USER));
+ reg_pt_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER);
+ reg_pt_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ reg_pt_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
/*
* Set address of the new pagetable by writng to IOMMU
* TTBR0 register
@@ -662,8 +670,11 @@
* tlb flush
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+ reg_pt_val = (pt_val + kgsl_mmu_get_default_ttbr0(
+ &device->mmu,
i, KGSL_IOMMU_CONTEXT_USER));
+ reg_pt_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ reg_pt_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
*cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
@@ -707,17 +718,20 @@
static unsigned int _adreno_iommu_setstate_v1(struct kgsl_device *device,
unsigned int *cmds_orig,
- unsigned int pt_val,
+ phys_addr_t pt_val,
int num_iommu_units, uint32_t flags)
{
+ phys_addr_t ttbr0_val;
unsigned int reg_pt_val;
unsigned int *cmds = cmds_orig;
int i;
unsigned int ttbr0, tlbiall, tlbstatus, tlbsync, mmu_ctrl;
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
- i, KGSL_IOMMU_CONTEXT_USER));
+ ttbr0_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER);
+ ttbr0_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ ttbr0_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
mmu_ctrl = kgsl_mmu_get_reg_ahbaddr(
&device->mmu, i,
@@ -753,8 +767,19 @@
KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE, 0xF);
}
/* set ttbr0 */
- *cmds++ = cp_type0_packet(ttbr0, 1);
- *cmds++ = reg_pt_val;
+ if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
+ reg_pt_val = ttbr0_val & 0xFFFFFFFF;
+ *cmds++ = cp_type0_packet(ttbr0, 1);
+ *cmds++ = reg_pt_val;
+ reg_pt_val = (unsigned int)
+ ((ttbr0_val & 0xFFFFFFFF00000000ULL) >> 32);
+ *cmds++ = cp_type0_packet(ttbr0 + 1, 1);
+ *cmds++ = reg_pt_val;
+ } else {
+ reg_pt_val = ttbr0_val;
+ *cmds++ = cp_type0_packet(ttbr0, 1);
+ *cmds++ = reg_pt_val;
+ }
if (kgsl_mmu_hw_halt_supported(&device->mmu, i)) {
/* unlock the IOMMU lock */
*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
@@ -796,7 +821,7 @@
unsigned int context_id,
uint32_t flags)
{
- unsigned int pt_val;
+ phys_addr_t pt_val;
unsigned int link[230];
unsigned int *cmds = &link[0];
int sizedwords = 0;
@@ -808,7 +833,8 @@
if (!adreno_dev->drawctxt_active ||
KGSL_STATE_ACTIVE != device->state ||
- !device->active_cnt) {
+ !device->active_cnt ||
+ device->cff_dump_enable) {
kgsl_mmu_device_setstate(&device->mmu, flags);
return;
}
@@ -891,7 +917,7 @@
* writes For CFF dump we must idle and use the registers so that it is
* easier to filter out the mmu accesses from the dump
*/
- if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) {
+ if (!device->cff_dump_enable && adreno_dev->drawctxt_active) {
context = idr_find(&device->context_idr, context_id);
if (context == NULL)
return;
@@ -1102,6 +1128,10 @@
adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
+ adreno_dev->pm4_jt_idx = adreno_gpulist[i].pm4_jt_idx;
+ adreno_dev->pm4_jt_addr = adreno_gpulist[i].pm4_jt_addr;
+ adreno_dev->pfp_jt_idx = adreno_gpulist[i].pfp_jt_idx;
+ adreno_dev->pfp_jt_addr = adreno_gpulist[i].pfp_jt_addr;
adreno_dev->gpulist_index = i;
}
@@ -1489,10 +1519,6 @@
&pdata->idle_timeout))
pdata->idle_timeout = HZ/12;
- if (adreno_of_read_property(pdev->dev.of_node, "qcom,nap-allowed",
- &pdata->nap_allowed))
- pdata->nap_allowed = 1;
-
pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
"qcom,strtstp-sleepwake");
@@ -1814,7 +1840,7 @@
/* Power down the device */
kgsl_pwrctrl_disable(device);
- kgsl_cffdump_close(device->id);
+ kgsl_cffdump_close(device);
return 0;
}
@@ -1861,11 +1887,11 @@
while ((context = idr_get_next(&device->context_idr, &next))) {
temp_adreno_context = context->devctxt;
if (temp_adreno_context->flags & CTXT_FLAGS_GPU_HANG) {
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context->id,
soptimestamp),
rb->timestamp[context->id]);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context->id,
eoptimestamp),
rb->timestamp[context->id]);
@@ -2163,10 +2189,70 @@
}
}
+/**
+ * adreno_soft_reset() - Do a soft reset of the GPU hardware
+ * @device: KGSL device to soft reset
+ *
+ * "soft reset" the GPU hardware - this is a fast path GPU reset
+ * The GPU hardware is reset but we never pull power so we can skip
+ * a lot of the standard adreno_stop/adreno_start sequence
+ */
+int adreno_soft_reset(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int ret;
+
+ /* If the jump table index is 0 soft reset is not supported */
+ if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+ dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
+ return -EINVAL;
+ }
+
+ adreno_dev->drawctxt_active = NULL;
+
+ /* Stop the ringbuffer */
+ adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+
+ /* Delete the idle timer */
+ del_timer_sync(&device->idle_timer);
+
+ /* Make sure we are totally awake */
+ kgsl_pwrctrl_enable(device);
+
+ /* Reset the GPU */
+ adreno_dev->gpudev->soft_reset(adreno_dev);
+
+ /* Reinitialize the GPU */
+ adreno_dev->gpudev->start(adreno_dev);
+
+ /* Enable IRQ */
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+ device->ftbl->irqctrl(device, 1);
+
+ /*
+ * Restart the ringbuffer - we can go down the warm start path because
+ * power was never yanked
+ */
+ ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+ if (ret)
+ return ret;
+
+ device->reset_counter++;
+
+ return 0;
+}
+
static int
_adreno_ft_restart_device(struct kgsl_device *device,
struct kgsl_context *context)
{
+ /* If device soft reset fails try hard reset */
+ if (adreno_soft_reset(device))
+ KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
+ else
+ /* Soft reset is successful */
+ goto reset_done;
+
/* restart device */
if (adreno_stop(device)) {
KGSL_FT_ERR(device, "Device stop failed\n");
@@ -2183,6 +2269,7 @@
return 1;
}
+reset_done:
if (context) {
struct adreno_context *adreno_context = context->devctxt;
kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
@@ -2289,6 +2376,7 @@
struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
unsigned int long_ib = 0;
static int no_context_ft;
+ struct kgsl_mmu *mmu = &device->mmu;
context = idr_find(&device->context_idr, ft_data->context_id);
if (context == NULL) {
@@ -2362,12 +2450,13 @@
/* Do not try the reply if hang is due to a pagefault */
if (adreno_context && adreno_context->pagefault) {
+ /* Resume MMU */
+ mmu->mmu_ops->mmu_pagefault_resume(mmu);
if ((ft_data->context_id == adreno_context->id) &&
(ft_data->global_eop == adreno_context->pagefault_ts)) {
ft_data->ft_policy &= ~KGSL_FT_REPLAY;
KGSL_FT_ERR(device, "MMU fault skipping replay\n");
}
-
adreno_context->pagefault = 0;
}
@@ -2542,7 +2631,7 @@
else
device->mmu.hwpagetable = device->mmu.defaultpagetable;
rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp;
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp),
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
@@ -2581,6 +2670,7 @@
INIT_COMPLETION(device->ft_gate);
/* Detected a hang */
+ kgsl_cffdump_hang(device);
/* Run fault tolerance at max power level */
curr_pwrlevel = pwr->active_pwrlevel;
kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
@@ -2741,8 +2831,6 @@
switch (type) {
case KGSL_PROP_PWRCTRL: {
unsigned int enable;
- struct kgsl_device_platform_data *pdata =
- kgsl_device_get_drvdata(device);
if (sizebytes != sizeof(enable))
break;
@@ -2754,12 +2842,11 @@
}
if (enable) {
- if (pdata->nap_allowed)
- device->pwrctrl.nap_allowed = true;
+ device->pwrctrl.ctrl_flags = 0;
adreno_dev->fast_hang_detect = 1;
kgsl_pwrscale_enable(device);
} else {
- device->pwrctrl.nap_allowed = false;
+ device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
adreno_dev->fast_hang_detect = 0;
kgsl_pwrscale_disable(device);
}
@@ -2822,7 +2909,7 @@
memset(prev_reg_val, 0, sizeof(prev_reg_val));
- kgsl_cffdump_regpoll(device->id,
+ kgsl_cffdump_regpoll(device,
adreno_dev->gpudev->reg_rbbm_status << 2,
0x00000000, 0x80000000);
@@ -2944,7 +3031,7 @@
/* Find a memory structure attached to an adreno context */
struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int size)
+ phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_context *context;
struct adreno_context *adreno_context = NULL;
@@ -2976,7 +3063,7 @@
}
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
- unsigned int pt_base,
+ phys_addr_t pt_base,
unsigned int gpuaddr,
unsigned int size)
{
@@ -3005,7 +3092,7 @@
return adreno_find_ctxtmem(device, pt_base, gpuaddr, size);
}
-uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
+uint8_t *adreno_convertaddr(struct kgsl_device *device, phys_addr_t pt_base,
unsigned int gpuaddr, unsigned int size)
{
struct kgsl_memdesc *memdesc;
@@ -3079,7 +3166,7 @@
kgsl_trace_regwrite(device, offsetwords, value);
- kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
+ kgsl_cffdump_regwrite(device, offsetwords << 2, value);
reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
/*ensure previous writes post before this one,
@@ -3139,18 +3226,18 @@
/* Make sure the memstore read has posted */
mb();
if (timestamp_cmp(ref_ts, timestamp) >= 0) {
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
/* Make sure the memstore write is posted */
wmb();
}
} else {
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
enableflag = 1;
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), enableflag);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 77b654b..782209d 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -110,6 +110,10 @@
unsigned int mharb;
struct adreno_gpudev *gpudev;
unsigned int wait_timeout;
+ unsigned int pm4_jt_idx;
+ unsigned int pm4_jt_addr;
+ unsigned int pfp_jt_idx;
+ unsigned int pfp_jt_addr;
unsigned int istore_size;
unsigned int pix_shader_start;
unsigned int instruction_size;
@@ -200,6 +204,7 @@
void (*coresight_disable) (struct kgsl_device *device);
void (*coresight_config_debug_reg) (struct kgsl_device *device,
int debug_reg, unsigned int val);
+ void (*soft_reset)(struct adreno_device *device);
};
/*
@@ -302,15 +307,15 @@
*adreno_dev);
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
- unsigned int pt_base,
+ phys_addr_t pt_base,
unsigned int gpuaddr,
unsigned int size);
uint8_t *adreno_convertaddr(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+ phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size);
struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+ phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size);
void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
int hang);
@@ -330,6 +335,9 @@
int adreno_perfcounter_put(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int countable);
+int adreno_soft_reset(struct kgsl_device *device);
+
+
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index dd9bdc3..b0a1fe8 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1364,8 +1364,9 @@
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
/* blank out gmem shadow. */
- kgsl_sharedmem_set(&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
- drawctxt->context_gmem_shadow.size);
+ kgsl_sharedmem_set(drawctxt->dev_priv->device,
+ &drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
+ drawctxt->context_gmem_shadow.size);
/* build quad vertex buffer */
build_quad_vtxbuff(drawctxt, &drawctxt->context_gmem_shadow,
@@ -1388,7 +1389,7 @@
kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow,
KGSL_CACHE_OP_FLUSH);
- kgsl_cffdump_syncmem(NULL,
+ kgsl_cffdump_syncmem(drawctxt->dev_priv,
&drawctxt->context_gmem_shadow.gmemshadow,
drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
drawctxt->context_gmem_shadow.gmemshadow.size, false);
@@ -1414,8 +1415,8 @@
if (ret)
return ret;
- kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0,
- _context_size(adreno_dev));
+ kgsl_sharedmem_set(drawctxt->dev_priv->device, &drawctxt->gpustate, 0,
+ 0, _context_size(adreno_dev));
tmp_ctx.cmd = tmp_ctx.start
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
@@ -1439,7 +1440,7 @@
kgsl_cache_range_op(&drawctxt->gpustate,
KGSL_CACHE_OP_FLUSH);
- kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
+ kgsl_cffdump_syncmem(drawctxt->dev_priv, &drawctxt->gpustate,
drawctxt->gpustate.gpuaddr,
drawctxt->gpustate.size, false);
@@ -1515,7 +1516,7 @@
"Current active context has caused gpu hang\n");
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->reg_save[1],
context->reg_save[2] << 2, true);
/* save registers and constants. */
@@ -1524,7 +1525,8 @@
context->reg_save, 3);
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->shader_save[1],
context->shader_save[2] << 2, true);
/* save shader partitioning and instructions. */
@@ -1532,7 +1534,8 @@
KGSL_CMD_FLAGS_PMODE,
context->shader_save, 3);
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->shader_fixup[1],
context->shader_fixup[2] << 2, true);
/*
@@ -1549,7 +1552,7 @@
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
/* save gmem.
@@ -1559,7 +1562,7 @@
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.gmem_save, 3);
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
@@ -1603,7 +1606,7 @@
* (note: changes shader. shader must not already be restored.)
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
true);
@@ -1613,7 +1616,8 @@
context->context_gmem_shadow.gmem_restore, 3);
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
@@ -1627,7 +1631,7 @@
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->reg_restore[1],
context->reg_restore[2] << 2, true);
@@ -1637,7 +1641,8 @@
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->shader_restore[1],
context->shader_restore[2] << 2, true);
@@ -1862,54 +1867,56 @@
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);
- GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 18));
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT,
+ 18));
/* All fields present (bits 9:0) */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x000003ff);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x000003ff);
/* Disable/Enable Real-Time Stream processing (present but ignored) */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE));
/* Instruction memory size: */
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
(adreno_encode_istore_size(adreno_dev)
| adreno_dev->pix_shader_start));
/* Maximum Contexts */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000001);
/* Write Confirm Interval and The CP will wait the
* wait_interval * 16 clocks between polling */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* NQ and External Memory Swap */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Protected mode error checking
* If iommu is used then protection needs to be turned off
* to enable context bank switching */
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
- GSL_RB_WRITE(cmds, cmds_gpu, 0);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0);
else
- GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
+ GSL_RB_PROTECTED_MODE_CONTROL);
/* Disable header dumping and Header dump address */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Header dump size */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
adreno_ringbuffer_submit(rb);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 1cdc87a..29855f7 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2360,7 +2360,8 @@
if (ret)
return ret;
- kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0, CONTEXT_SIZE);
+ kgsl_sharedmem_set(&adreno_dev->dev, &drawctxt->gpustate, 0, 0,
+ CONTEXT_SIZE);
tmp_ctx.cmd = drawctxt->gpustate.hostptr + CMD_OFFSET;
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
@@ -2419,7 +2420,7 @@
* already be saved.)
*/
- kgsl_cffdump_syncmem(NULL,
+ kgsl_cffdump_syncmem(context->dev_priv,
&context->gpustate,
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
@@ -2461,7 +2462,7 @@
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
- kgsl_cffdump_syncmem(NULL,
+ kgsl_cffdump_syncmem(context->dev_priv,
&context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
@@ -2509,25 +2510,26 @@
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint) * (rb->wptr - 18);
- GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 17));
- GSL_RB_WRITE(cmds, cmds_gpu, 0x000003f7);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000080);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000100);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000180);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00006600);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000150);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x0000014e);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000154);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
+ cp_type3_packet(CP_ME_INIT, 17));
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x000003f7);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000080);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000100);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000180);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00006600);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000150);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x0000014e);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000154);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000001);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Protected mode control - turned off for A3XX */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
adreno_ringbuffer_submit(rb);
@@ -3459,6 +3461,30 @@
ARRAY_SIZE(a3xx_perfcounter_groups),
};
+/*
+ * a3xx_soft_reset() - Soft reset GPU
+ * @adreno_dev: Pointer to adreno device
+ *
+ * Soft reset the GPU by doing a AHB write of value 1 to RBBM_SW_RESET
+ * register. This is used when we want to reset the GPU without
+ * turning off GFX power rail. The reset when asserted resets
+ * all the HW logic, restores GPU registers to default state and
+ * flushes out pending VBIF transactions.
+ */
+static void a3xx_soft_reset(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ unsigned int reg;
+
+ adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 1);
+ /*
+ * Do a dummy read to get a brief read cycle delay for the reset to take
+ * effect
+ */
+ adreno_regread(device, A3XX_RBBM_SW_RESET_CMD, ®);
+ adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 0);
+}
+
/* Defined in adreno_a3xx_snapshot.c */
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
int *remain, int hang);
@@ -3486,4 +3512,5 @@
.coresight_enable = a3xx_coresight_enable,
.coresight_disable = a3xx_coresight_disable,
.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
+ .soft_reset = a3xx_soft_reset,
};
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 980ff13..12b9e7c 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -19,27 +19,12 @@
#include "kgsl.h"
#include "adreno.h"
+#include "kgsl_cffdump.h"
#include "a2xx_reg.h"
unsigned int kgsl_cff_dump_enable;
-static int kgsl_cff_dump_enable_set(void *data, u64 val)
-{
-#ifdef CONFIG_MSM_KGSL_CFF_DUMP
- kgsl_cff_dump_enable = (val != 0);
- return 0;
-#else
- return -EINVAL;
-#endif
-}
-
-static int kgsl_cff_dump_enable_get(void *data, u64 *val)
-{
- *val = kgsl_cff_dump_enable;
- return 0;
-}
-
DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
kgsl_cff_dump_enable_set, "%llu\n");
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 176717d..b32cdae 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -192,19 +192,20 @@
drawctxt->type =
(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;
+ drawctxt->dev_priv = context->dev_priv;
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
KGSL_INIT_REFTIMESTAMP);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
context->devctxt = drawctxt;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index f0f3b6b..2b8e600 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -131,6 +131,7 @@
struct kgsl_memdesc constant_load_commands[3];
struct kgsl_memdesc cond_execs[4];
struct kgsl_memdesc hlsqcontrol_restore_commands[1];
+ struct kgsl_device_private *dev_priv;
};
int adreno_drawctxt_create(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 2249907..c7b6b5b 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -190,8 +190,9 @@
}
}
-static void dump_ib(struct kgsl_device *device, char* buffId, uint32_t pt_base,
- uint32_t base_offset, uint32_t ib_base, uint32_t ib_size, bool dump)
+static void dump_ib(struct kgsl_device *device, char *buffId,
+ phys_addr_t pt_base, uint32_t base_offset, uint32_t ib_base,
+ uint32_t ib_size, bool dump)
{
uint8_t *base_addr = adreno_convertaddr(device, pt_base,
ib_base, ib_size*sizeof(uint32_t));
@@ -214,7 +215,7 @@
uint32_t offsets[IB_LIST_SIZE];
};
-static void dump_ib1(struct kgsl_device *device, uint32_t pt_base,
+static void dump_ib1(struct kgsl_device *device, phys_addr_t pt_base,
uint32_t base_offset,
uint32_t ib1_base, uint32_t ib1_size,
struct ib_list *ib_list, bool dump)
@@ -719,7 +720,7 @@
{
unsigned int cp_ib1_base, cp_ib1_bufsz;
unsigned int cp_ib2_base, cp_ib2_bufsz;
- unsigned int pt_base, cur_pt_base;
+ phys_addr_t pt_base, cur_pt_base;
unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
unsigned int cp_rb_wptr, cp_rb_rptr;
unsigned int i;
@@ -862,20 +863,20 @@
&device->mmu, 0,
KGSL_IOMMU_CONTEXT_USER,
KGSL_IOMMU_CTX_TTBR0), 1))) {
- KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
- "pagetable base: %x\n",
+ KGSL_LOG_DUMP(device,
+ "Current pagetable: %x\t pagetable base: %pa\n",
kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
cur_pt_base),
- cur_pt_base);
+ &cur_pt_base);
/* Set cur_pt_base to the new pagetable base */
cur_pt_base = rb_copy[read_idx++];
- KGSL_LOG_DUMP(device, "New pagetable: %x\t"
- "pagetable base: %x\n",
+ KGSL_LOG_DUMP(device,
+ "New pagetable: %x\t pagetable base: %pa\n",
kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
cur_pt_base),
- cur_pt_base);
+ &cur_pt_base);
}
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 61ea916..d12853f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/log2.h>
+#include <linux/time.h>
+#include <linux/delay.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
@@ -76,7 +78,8 @@
cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
- GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
+ cp_nop_packet(nopcount));
/* Make sure that rptr is not 0 before submitting
* commands at the end of ringbuffer. We do not
@@ -241,8 +244,16 @@
return ret;
}
-
-int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
+/**
+ * adreno_ringbuffer_load_pm4_ucode() - Load pm4 ucode
+ * @device: Pointer to a KGSL device
+ * @start: Starting index in pm4 ucode to load
+ * @addr: Address to load the pm4 ucode
+ *
+ * Load the pm4 ucode from @start at @addr.
+ */
+int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device,
+ unsigned int start, unsigned int addr)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
@@ -257,8 +268,8 @@
adreno_dev->pm4_fw_version);
adreno_regwrite(device, REG_CP_DEBUG, CP_DEBUG_DEFAULT);
- adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
- for (i = 1; i < adreno_dev->pm4_fw_size; i++)
+ adreno_regwrite(device, REG_CP_ME_RAM_WADDR, addr);
+ for (i = start; i < adreno_dev->pm4_fw_size; i++)
adreno_regwrite(device, REG_CP_ME_RAM_DATA,
adreno_dev->pm4_fw[i]);
@@ -296,7 +307,16 @@
return ret;
}
-int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
+/**
+ * adreno_ringbuffer_load_pfp_ucode() - Load pfp ucode
+ * @device: Pointer to a KGSL device
+ * @start: Starting index in pfp ucode to load
+ * @addr: Address to load the pfp ucode
+ *
+ * Load the pfp ucode from @start at @addr.
+ */
+int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device,
+ unsigned int start, unsigned int addr)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
@@ -310,8 +330,9 @@
KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
adreno_dev->pfp_fw_version);
- adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
- for (i = 1; i < adreno_dev->pfp_fw_size; i++)
+ adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr,
+ addr);
+ for (i = start; i < adreno_dev->pfp_fw_size; i++)
adreno_regwrite(device,
adreno_dev->gpudev->reg_cp_pfp_ucode_data,
adreno_dev->pfp_fw[i]);
@@ -319,7 +340,13 @@
return 0;
}
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
+/**
+ * _ringbuffer_start_common() - Ringbuffer start
+ * @rb: Pointer to adreno ringbuffer
+ *
+ * Setup ringbuffer for GPU.
+ */
+int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
{
int status;
/*cp_rb_cntl_u cp_rb_cntl; */
@@ -331,10 +358,10 @@
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
- kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
+ kgsl_sharedmem_set(rb->device, &rb->memptrs_desc, 0, 0,
sizeof(struct kgsl_rbmemptrs));
- kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
+ kgsl_sharedmem_set(rb->device, &rb->buffer_desc, 0, 0xAA,
(rb->sizedwords << 2));
if (adreno_is_a2xx(adreno_dev)) {
@@ -419,16 +446,6 @@
adreno_regwrite(device, REG_SCRATCH_UMSK,
GSL_RB_MEMPTRS_SCRATCH_MASK);
- /* load the CP ucode */
- status = adreno_ringbuffer_load_pm4_ucode(device);
- if (status != 0)
- return status;
-
- /* load the prefetch parser ucode */
- status = adreno_ringbuffer_load_pfp_ucode(device);
- if (status != 0)
- return status;
-
/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
if (adreno_is_a305(adreno_dev) || adreno_is_a305c(adreno_dev) ||
adreno_is_a320(adreno_dev))
@@ -456,6 +473,54 @@
return status;
}
+/**
+ * adreno_ringbuffer_warm_start() - Ringbuffer warm start
+ * @rb: Pointer to adreno ringbuffer
+ *
+ * Start the ringbuffer but load only jump tables part of the
+ * microcode.
+ */
+int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb)
+{
+ int status;
+ struct kgsl_device *device = rb->device;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* load the CP ucode */
+ status = adreno_ringbuffer_load_pm4_ucode(device,
+ adreno_dev->pm4_jt_idx, adreno_dev->pm4_jt_addr);
+ if (status != 0)
+ return status;
+
+ /* load the prefetch parser ucode */
+ status = adreno_ringbuffer_load_pfp_ucode(device,
+ adreno_dev->pfp_jt_idx, adreno_dev->pfp_jt_addr);
+ if (status != 0)
+ return status;
+
+ return _ringbuffer_start_common(rb);
+}
+
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
+{
+ int status;
+
+ if (rb->flags & KGSL_FLAGS_STARTED)
+ return 0;
+
+ /* load the CP ucode */
+ status = adreno_ringbuffer_load_pm4_ucode(rb->device, 1, 0);
+ if (status != 0)
+ return status;
+
+ /* load the prefetch parser ucode */
+ status = adreno_ringbuffer_load_pfp_ucode(rb->device, 1, 0);
+ if (status != 0)
+ return status;
+
+ return _ringbuffer_start_common(rb);
+}
+
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
{
struct kgsl_device *device = rb->device;
@@ -612,12 +677,13 @@
rcmd_gpu = rb->buffer_desc.gpuaddr
+ sizeof(uint)*(rb->wptr-total_sizedwords);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
if (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_INTERNAL_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ KGSL_CMD_INTERNAL_IDENTIFIER);
}
/* always increment the global timestamp. once. */
@@ -636,32 +702,35 @@
timestamp = rb->timestamp[context_id];
/* scratchpad ts for fault tolerance */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type0_packet(REG_CP_TIMESTAMP, 1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
/* start-of-pipeline timestamp */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
if (flags & KGSL_CMD_FLAGS_PMODE) {
/* disable protected mode error checking */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
}
for (i = 0; i < sizedwords; i++) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, *cmds);
cmds++;
}
if (flags & KGSL_CMD_FLAGS_PMODE) {
/* re-enable protected mode error checking */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 1);
}
/* HW Workaround for MMU Page fault
@@ -669,9 +738,9 @@
* GPU completes it.
*/
if (adreno_is_a2xx(adreno_dev)) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00);
}
if (adreno_is_a3xx(adreno_dev)) {
@@ -680,12 +749,13 @@
* resources pending for indirect loads after the timestamp
*/
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_EVENT_WRITE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds,
+ rcmd_gpu, 0x07); /* HLSQ_FLUSH */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00);
}
/*
@@ -693,62 +763,64 @@
* enabled, then context_id will be KGSL_MEMSTORE_GLOBAL so all
* eop timestamps will work out.
*/
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_EVENT_WRITE, 3));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
if (KGSL_MEMSTORE_GLOBAL != context_id) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
}
if (adreno_is_a20x(adreno_dev)) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_EVENT_WRITE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH);
}
if (context) {
/* Conditional execution based on memory values */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ts_cmp_enable)) >> 2);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ref_wait_ts)) >> 2);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
/* # of conditional command DWORDs */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 8);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 8);
/* Clear the ts_cmp_enable for the context */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ts_cmp_enable));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
/* Clear the ts_cmp_enable for the global timestamp */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
KGSL_MEMSTORE_OFFSET(
KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
/* Trigger the interrupt */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_INTERRUPT, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ CP_INT_CNTL__RB_INT_MASK);
}
/*
@@ -758,24 +830,25 @@
if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
KGSL_CMD_FLAGS_GET_INT))) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_INTERRUPT, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
CP_INT_CNTL__RB_INT_MASK);
}
if (adreno_is_a3xx(adreno_dev)) {
/* Dummy set-constant to trigger context rollover */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_SET_CONSTANT, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
(0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
}
if (flags & KGSL_CMD_FLAGS_EOF) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_END_OF_FRAME_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ KGSL_END_OF_FRAME_IDENTIFIER);
}
adreno_ringbuffer_submit(rb);
@@ -1150,7 +1223,8 @@
if (val[i] == cp_nop_packet(4)) {
temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
temp_rb_rptr, size);
- kgsl_sharedmem_writel(&rb->buffer_desc,
+ kgsl_sharedmem_writel(rb->device,
+ &rb->buffer_desc,
temp_rb_rptr, cp_nop_packet(1));
}
KGSL_FT_INFO(rb->device,
@@ -1312,7 +1386,7 @@
ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
for (i = 0; i < num_rb_contents; i++)
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, rb_buff[i]);
rb->wptr += num_rb_contents;
adreno_ringbuffer_submit(rb);
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index e563ec7..f59b834 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -60,11 +60,11 @@
};
-#define GSL_RB_WRITE(ring, gpuaddr, data) \
+#define GSL_RB_WRITE(device, ring, gpuaddr, data) \
do { \
*ring = data; \
wmb(); \
- kgsl_cffdump_setmem(gpuaddr, data, 4); \
+ kgsl_cffdump_setmem(device, gpuaddr, data, 4); \
ring++; \
gpuaddr += sizeof(uint); \
} while (0)
@@ -97,6 +97,8 @@
int adreno_ringbuffer_init(struct kgsl_device *device);
+int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb);
+
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb);
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 144c3d6..d6ce298 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -34,7 +34,7 @@
static struct kgsl_snapshot_obj {
int type;
uint32_t gpuaddr;
- uint32_t ptbase;
+ phys_addr_t ptbase;
void *ptr;
int dwords;
} objbuf[SNAPSHOT_OBJ_BUFSIZE];
@@ -43,7 +43,8 @@
static int objbufptr;
/* Push a new buffer object onto the list */
-static void push_object(struct kgsl_device *device, int type, uint32_t ptbase,
+static void push_object(struct kgsl_device *device, int type,
+ phys_addr_t ptbase,
uint32_t gpuaddr, int dwords)
{
int index;
@@ -94,7 +95,7 @@
* to be dumped
*/
-static int find_object(int type, unsigned int gpuaddr, unsigned int ptbase)
+static int find_object(int type, unsigned int gpuaddr, phys_addr_t ptbase)
{
int index;
@@ -184,7 +185,7 @@
};
static int ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
unsigned int block, source, type;
int ret = 0;
@@ -243,7 +244,7 @@
*/
static int ib_parse_set_bin_data(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int ret;
@@ -276,7 +277,7 @@
*/
static int ib_parse_mem_write(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int ret;
@@ -307,7 +308,7 @@
*/
static int ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int ret = 0, i;
@@ -439,7 +440,7 @@
*/
static int ib_parse_type3(struct kgsl_device *device, unsigned int *ptr,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int opcode = cp_type3_opcode(*ptr);
@@ -464,7 +465,7 @@
*/
static void ib_parse_type0(struct kgsl_device *device, unsigned int *ptr,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int size = type0_pkt_size(*ptr);
int offset = type0_pkt_offset(*ptr);
@@ -542,12 +543,12 @@
}
}
-static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase,
+static inline int parse_ib(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords);
/* Add an IB as a GPU object, but first, parse it to find more goodies within */
-static int ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase,
+static int ib_add_gpu_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords)
{
int i, ret, rem = dwords;
@@ -625,7 +626,7 @@
* access the dynamic data from the sysfs file. Push all other IBs on the
* dynamic list
*/
-static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase,
+static inline int parse_ib(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords)
{
unsigned int ib1base, ib2base;
@@ -657,7 +658,8 @@
unsigned int *data = snapshot + sizeof(*header);
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned int ptbase, rptr, *rbptr, ibbase;
+ unsigned int rptr, *rbptr, ibbase;
+ phys_addr_t ptbase;
int index, size, i;
int parse_ibs = 0, ib_parse_start;
@@ -824,7 +826,7 @@
struct kgsl_snapshot_replay_mem_list *header = snapshot;
struct kgsl_process_private *private = NULL;
struct kgsl_process_private *tmp_private;
- unsigned int ptbase;
+ phys_addr_t ptbase;
struct rb_node *node;
struct kgsl_mem_entry *entry = NULL;
int num_mem;
@@ -861,7 +863,7 @@
return 0;
}
header->num_entries = num_mem;
- header->ptbase = ptbase;
+ header->ptbase = (__u32)ptbase;
/*
* Walk throught the memory list and store the
* tuples(gpuaddr, size, memtype) in snapshot
@@ -897,7 +899,7 @@
/* Write the sub-header for the section */
header->gpuaddr = obj->gpuaddr;
- header->ptbase = obj->ptbase;
+ header->ptbase = (__u32)obj->ptbase;
header->size = obj->dwords;
/* Write the contents of the ib */
@@ -957,8 +959,9 @@
int hang)
{
int i;
- uint32_t ptbase, ibbase, ibsize;
+ uint32_t ibbase, ibsize;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ phys_addr_t ptbase;
/* Reset the list of objects */
objbufptr = 0;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fb31dd6..1d2c341 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -18,17 +18,18 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
-
+#include <linux/dma-buf.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include <linux/genlock.h>
#include <linux/rbtree.h>
#include <linux/ashmem.h>
#include <linux/major.h>
-#include <linux/msm_ion.h>
#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"
@@ -51,7 +52,11 @@
MODULE_PARM_DESC(ksgl_mmu_type,
"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
-static struct ion_client *kgsl_ion_client;
+struct kgsl_dma_buf_meta {
+ struct dma_buf_attachment *attach;
+ struct dma_buf *dmabuf;
+ struct sg_table *table;
+};
/**
* kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
@@ -149,8 +154,8 @@
*/
struct kgsl_mem_entry * __must_check
-kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase,
- unsigned int gpuaddr, unsigned int size)
+kgsl_get_mem_entry(struct kgsl_device *device,
+ phys_addr_t ptbase, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -186,6 +191,14 @@
return entry;
}
+static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+{
+ dma_buf_unmap_attachment(meta->attach, meta->table, DMA_FROM_DEVICE);
+ dma_buf_detach(meta->dmabuf, meta->attach);
+ dma_buf_put(meta->dmabuf);
+ kfree(meta);
+}
+
void
kgsl_mem_entry_destroy(struct kref *kref)
{
@@ -215,7 +228,7 @@
fput(entry->priv_data);
break;
case KGSL_MEM_ENTRY_ION:
- ion_free(kgsl_ion_client, entry->priv_data);
+ kgsl_destroy_ion(entry->priv_data);
break;
}
@@ -512,7 +525,6 @@
static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
{
int status = -EINVAL;
- unsigned int nap_allowed_saved;
struct kgsl_pwrscale_policy *policy_saved;
if (!device)
@@ -521,8 +533,6 @@
KGSL_PWR_WARN(device, "suspend start\n");
mutex_lock(&device->mutex);
- nap_allowed_saved = device->pwrctrl.nap_allowed;
- device->pwrctrl.nap_allowed = false;
policy_saved = device->pwrscale.policy;
device->pwrscale.policy = NULL;
kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
@@ -532,6 +542,12 @@
*/
kgsl_active_count_wait(device);
+ /*
+ * An interrupt could have snuck in and requested NAP in
+ * the meantime, make sure we're on the SUSPEND path.
+ */
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
+
/* Don't let the timer wake us during suspended sleep. */
del_timer_sync(&device->idle_timer);
switch (device->state) {
@@ -562,7 +578,6 @@
goto end;
}
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
- device->pwrctrl.nap_allowed = nap_allowed_saved;
device->pwrscale.policy = policy_saved;
status = 0;
@@ -574,23 +589,32 @@
static int kgsl_resume_device(struct kgsl_device *device)
{
- int status = -EINVAL;
-
if (!device)
return -EINVAL;
KGSL_PWR_WARN(device, "resume start\n");
mutex_lock(&device->mutex);
if (device->state == KGSL_STATE_SUSPEND) {
- kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
- status = 0;
complete_all(&device->hwaccess_gate);
+ } else {
+ /*
+ * This is an error situation,so wait for the device
+ * to idle and then put the device to SLUMBER state.
+ * This will put the device to the right state when
+ * we resume.
+ */
+ device->ftbl->idle(device);
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
+ kgsl_pwrctrl_sleep(device);
+ KGSL_PWR_ERR(device,
+ "resume invoked without a suspend\n");
}
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
mutex_unlock(&device->mutex);
KGSL_PWR_WARN(device, "resume end\n");
- return status;
+ return 0;
}
static int kgsl_suspend(struct device *dev)
@@ -801,6 +825,27 @@
return private;
}
+int kgsl_close_device(struct kgsl_device *device)
+{
+ int result = 0;
+ device->open_count--;
+ if (device->open_count == 0) {
+ BUG_ON(device->active_cnt > 1);
+ result = device->ftbl->stop(device);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ /*
+ * active_cnt special case: we just stopped the device,
+ * so no need to use kgsl_active_count_put()
+ */
+ device->active_cnt--;
+ } else {
+ kgsl_active_count_put(device);
+ }
+ return result;
+
+}
+EXPORT_SYMBOL(kgsl_close_device);
+
static int kgsl_release(struct inode *inodep, struct file *filep)
{
int result = 0;
@@ -820,8 +865,10 @@
if (context == NULL)
break;
- if (context->dev_priv == dev_priv)
+ if (context->dev_priv == dev_priv) {
kgsl_context_detach(context);
+ context->dev_priv = NULL;
+ }
next = next + 1;
}
@@ -833,19 +880,7 @@
*/
kgsl_cancel_events(device, dev_priv);
- device->open_count--;
- if (device->open_count == 0) {
- BUG_ON(device->active_cnt > 1);
- result = device->ftbl->stop(device);
- kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
- /*
- * active_cnt special case: we just stopped the device,
- * so no need to use kgsl_active_count_put()
- */
- device->active_cnt--;
- } else {
- kgsl_active_count_put(device);
- }
+ result = kgsl_close_device(device);
mutex_unlock(&device->mutex);
kfree(dev_priv);
@@ -855,6 +890,43 @@
return result;
}
+int kgsl_open_device(struct kgsl_device *device)
+{
+ int result = 0;
+ if (device->open_count == 0) {
+ /*
+ * active_cnt special case: we are starting up for the first
+ * time, so use this sequence instead of the kgsl_pwrctrl_wake()
+ * which will be called by kgsl_active_count_get().
+ */
+ device->active_cnt++;
+ kgsl_sharedmem_set(device, &device->memstore, 0, 0,
+ device->memstore.size);
+
+ result = device->ftbl->init(device);
+ if (result)
+ goto err;
+
+ result = device->ftbl->start(device);
+ if (result)
+ goto err;
+ /*
+ * Make sure the gates are open, so they don't block until
+ * we start suspend or FT.
+ */
+ complete_all(&device->ft_gate);
+ complete_all(&device->hwaccess_gate);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ kgsl_active_count_put(device);
+ }
+ device->open_count++;
+err:
+ if (result)
+ device->active_cnt--;
+ return result;
+}
+EXPORT_SYMBOL(kgsl_open_device);
+
static int kgsl_open(struct inode *inodep, struct file *filep)
{
int result;
@@ -892,33 +964,9 @@
mutex_lock(&device->mutex);
- if (device->open_count == 0) {
- /*
- * active_cnt special case: we are starting up for the first
- * time, so use this sequence instead of the kgsl_pwrctrl_wake()
- * which will be called by kgsl_active_count_get().
- */
- device->active_cnt++;
- kgsl_sharedmem_set(&device->memstore, 0, 0,
- device->memstore.size);
-
- result = device->ftbl->init(device);
- if (result)
- goto err_freedevpriv;
-
- result = device->ftbl->start(device);
- if (result)
- goto err_freedevpriv;
- /*
- * Make sure the gates are open, so they don't block until
- * we start suspend or FT.
- */
- complete_all(&device->ft_gate);
- complete_all(&device->hwaccess_gate);
- kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
- kgsl_active_count_put(device);
- }
- device->open_count++;
+ result = kgsl_open_device(device);
+ if (result)
+ goto err_freedevpriv;
mutex_unlock(&device->mutex);
/*
@@ -946,11 +994,9 @@
kgsl_pwrctrl_enable(device);
result = device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ device->active_cnt--;
}
err_freedevpriv:
- /* only the first open takes an active count */
- if (device->open_count == 0)
- device->active_cnt--;
mutex_unlock(&device->mutex);
filep->private_data = NULL;
kfree(dev_priv);
@@ -1842,38 +1888,55 @@
#endif
static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
- struct kgsl_pagetable *pagetable, void *data)
+ struct kgsl_pagetable *pagetable, void *data,
+ struct kgsl_device *device)
{
- struct ion_handle *handle;
struct scatterlist *s;
struct sg_table *sg_table;
struct kgsl_map_user_mem *param = data;
int fd = param->fd;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attach;
+ struct kgsl_dma_buf_meta *meta;
+ int ret;
if (!param->len)
return -EINVAL;
- if (IS_ERR_OR_NULL(kgsl_ion_client))
- return -ENODEV;
+ meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+ if (!meta)
+ return -ENOMEM;
- handle = ion_import_dma_buf(kgsl_ion_client, fd);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- else if (!handle)
- return -EINVAL;
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ ret = PTR_ERR(dmabuf);
+ goto err1;
+ }
+
+ attach = dma_buf_attach(dmabuf, device->dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ ret = PTR_ERR(attach);
+ goto err2;
+ }
+
+ meta->dmabuf = dmabuf;
+ meta->attach = attach;
entry->memtype = KGSL_MEM_ENTRY_ION;
- entry->priv_data = handle;
+ entry->priv_data = meta;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = 0;
/* USE_CPU_MAP is not impemented for ION. */
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
- sg_table = ion_sg_table(kgsl_ion_client, handle);
+ sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
- if (IS_ERR_OR_NULL(sg_table))
- goto err;
+ if (IS_ERR_OR_NULL(sg_table)) {
+ ret = PTR_ERR(sg_table);
+ goto err3;
+ }
+ meta->table = sg_table;
entry->memdesc.sg = sg_table->sgl;
/* Calculate the size of the memdesc from the sglist */
@@ -1888,9 +1951,13 @@
entry->memdesc.size = PAGE_ALIGN(entry->memdesc.size);
return 0;
-err:
- ion_free(kgsl_ion_client, handle);
- return -ENOMEM;
+err3:
+ dma_buf_detach(dmabuf, attach);
+err2:
+ dma_buf_put(dmabuf);
+err1:
+ kfree(meta);
+ return ret;
}
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
@@ -1978,7 +2045,8 @@
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
break;
case KGSL_USER_MEM_TYPE_ION:
- result = kgsl_setup_ion(entry, private->pagetable, data);
+ result = kgsl_setup_ion(entry, private->pagetable, data,
+ dev_priv->device);
break;
default:
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
@@ -2025,7 +2093,7 @@
fput(entry->priv_data);
break;
case KGSL_MEM_ENTRY_ION:
- ion_free(kgsl_ion_client, entry->priv_data);
+ kgsl_destroy_ion(entry->priv_data);
break;
default:
break;
@@ -2104,6 +2172,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
@@ -2312,7 +2471,8 @@
int result = 0;
struct kgsl_cff_user_event *param = data;
- kgsl_cffdump_user_event(param->cff_opcode, param->op1, param->op2,
+ kgsl_cffdump_user_event(dev_priv->device, param->cff_opcode,
+ param->op1, param->op2,
param->op3, param->op4, param->op5);
return result;
@@ -2510,6 +2670,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)
@@ -2809,16 +2971,17 @@
ret = ALIGN(ret, (1 << align));
/*make sure there isn't a GPU only mapping at this address */
- if (kgsl_sharedmem_region_empty(private, ret, len))
+ if (kgsl_sharedmem_region_empty(private, ret, orig_len))
break;
- trace_kgsl_mem_unmapped_area_collision(entry, addr, len, ret);
+ trace_kgsl_mem_unmapped_area_collision(entry, addr, orig_len,
+ ret);
/*
* If we collided, bump the hint address so that
* get_umapped_area knows to look somewhere else.
*/
- addr = (addr == 0) ? ret + len : addr + len;
+ addr = (addr == 0) ? ret + orig_len : addr + orig_len;
/*
* The addr hint can be set by userspace to be near
@@ -2952,6 +3115,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);
@@ -3032,8 +3200,6 @@
if (status)
goto error;
- kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
-
/* Get starting physical address of device registers */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
device->iomemname);
@@ -3172,12 +3338,11 @@
int kgsl_postmortem_dump(struct kgsl_device *device, int manual)
{
- bool saved_nap;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
BUG_ON(device == NULL);
- kgsl_cffdump_hang(device->id);
+ kgsl_cffdump_hang(device);
/* For a manual dump, make sure that the system is idle */
@@ -3192,8 +3357,8 @@
if (device->pm_dump_enable) {
KGSL_LOG_DUMP(device,
- "POWER: NAP ALLOWED = %d | START_STOP_SLEEP_WAKE = %d\n"
- , pwr->nap_allowed, pwr->strtstp_sleepwake);
+ "POWER: START_STOP_SLEEP_WAKE = %d\n",
+ pwr->strtstp_sleepwake);
KGSL_LOG_DUMP(device,
"POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
@@ -3210,11 +3375,6 @@
flush_workqueue(device->work_queue);
mutex_lock(&device->mutex);
- /* Turn off napping to make sure we have the clocks full
- attention through the following process */
- saved_nap = device->pwrctrl.nap_allowed;
- device->pwrctrl.nap_allowed = false;
-
/* Force on the clocks */
kgsl_pwrctrl_wake(device);
@@ -3224,9 +3384,6 @@
/*Call the device specific postmortem dump function*/
device->ftbl->postmortem_dump(device, manual);
- /* Restore nap mode */
- device->pwrctrl.nap_allowed = saved_nap;
-
/* On a manual trigger, turn on the interrupts and put
the clocks to sleep. They will recover themselves
on the next event. For a hang, leave things as they
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index c7cbaf8..4a1f291 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;
@@ -206,7 +207,7 @@
int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
- unsigned int ptbase, unsigned int gpuaddr, unsigned int size);
+ phys_addr_t ptbase, unsigned int gpuaddr, unsigned int size);
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
struct kgsl_process_private *private, unsigned int gpuaddr,
@@ -237,6 +238,10 @@
unsigned int timestamp, unsigned int flags,
int result, unsigned int type);
+int kgsl_open_device(struct kgsl_device *device);
+
+int kgsl_close_device(struct kgsl_device *device);
+
#ifdef CONFIG_MSM_KGSL_DRM
extern int kgsl_drm_init(struct platform_device *dev);
extern void kgsl_drm_exit(void);
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index c3bdf80..99f4235 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -335,8 +335,6 @@
return;
}
- kgsl_cff_dump_enable = 0;
-
spin_lock_init(&cffdump_lock);
dir = debugfs_create_dir("cff", debugfs_dir);
@@ -360,53 +358,54 @@
void kgsl_cffdump_open(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
- kgsl_cffdump_memory_base(device->id,
+ kgsl_cffdump_memory_base(device,
KGSL_PAGETABLE_BASE,
KGSL_IOMMU_GLOBAL_MEM_BASE +
KGSL_IOMMU_GLOBAL_MEM_SIZE -
KGSL_PAGETABLE_BASE,
adreno_dev->gmem_size);
} else {
- kgsl_cffdump_memory_base(device->id,
+ kgsl_cffdump_memory_base(device,
kgsl_mmu_get_base_addr(&device->mmu),
kgsl_mmu_get_ptsize(&device->mmu),
adreno_dev->gmem_size);
}
}
-void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
+void kgsl_cffdump_memory_base(struct kgsl_device *device, unsigned int base,
unsigned int range, unsigned gmemsize)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base,
+ cffdump_printline(device->id, CFF_OP_MEMORY_BASE, base,
range, gmemsize, 0, 0);
}
-void kgsl_cffdump_hang(enum kgsl_deviceid device_id)
+void kgsl_cffdump_hang(struct kgsl_device *device)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0);
+ cffdump_printline(device->id, CFF_OP_HANG, 0, 0, 0, 0, 0);
}
-void kgsl_cffdump_close(enum kgsl_deviceid device_id)
+void kgsl_cffdump_close(struct kgsl_device *device)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0);
+ cffdump_printline(device->id, CFF_OP_EOF, 0, 0, 0, 0, 0);
}
-void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
+void kgsl_cffdump_user_event(struct kgsl_device *device,
+ unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
}
@@ -415,9 +414,10 @@
struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes,
bool clean_cache)
{
+ struct kgsl_device *device = dev_priv->device;
const void *src;
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
total_syncmem += sizebytes;
@@ -437,9 +437,9 @@
}
src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
if (memdesc->hostptr == NULL) {
- KGSL_CORE_ERR("no kernel mapping for "
- "gpuaddr: 0x%08x, m->host: 0x%p, phys: 0x%08x\n",
- gpuaddr, memdesc->hostptr, memdesc->physaddr);
+ KGSL_CORE_ERR(
+ "no kernel map for gpuaddr: 0x%08x, m->host: 0x%p, phys: %pa\n",
+ gpuaddr, memdesc->hostptr, &memdesc->physaddr);
return;
}
@@ -465,9 +465,10 @@
0, 0, 0);
}
-void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes)
+void kgsl_cffdump_setmem(struct kgsl_device *device,
+ uint addr, uint value, uint sizebytes)
{
- if (!kgsl_cff_dump_enable)
+ if (!device || !device->cff_dump_enable)
return;
while (sizebytes > 3) {
@@ -483,37 +484,37 @@
0, 0, 0);
}
-void kgsl_cffdump_regwrite(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_regwrite(struct kgsl_device *device, uint addr,
uint value)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_WRITE_REG, addr, value,
+ cffdump_printline(device->id, CFF_OP_WRITE_REG, addr, value,
0, 0, 0);
}
-void kgsl_cffdump_regpoll(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_regpoll(struct kgsl_device *device, uint addr,
uint value, uint mask)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_POLL_REG, addr, value,
+ cffdump_printline(device->id, CFF_OP_POLL_REG, addr, value,
mask, 0, 0);
}
-void kgsl_cffdump_slavewrite(uint addr, uint value)
+void kgsl_cffdump_slavewrite(struct kgsl_device *device, uint addr, uint value)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
cffdump_printline(-1, CFF_OP_WRITE_REG, addr, value, 0, 0, 0);
}
-int kgsl_cffdump_waitirq(void)
+int kgsl_cffdump_waitirq(struct kgsl_device *device)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return 0;
cffdump_printline(-1, CFF_OP_WAIT_IRQ, 0, 0, 0, 0, 0);
@@ -614,3 +615,59 @@
}
}
+int kgsl_cff_dump_enable_set(void *data, u64 val)
+{
+ int ret = 0;
+ struct kgsl_device *device = (struct kgsl_device *)data;
+ int i;
+
+ mutex_lock(&kgsl_driver.devlock);
+ /*
+ * If CFF dump enabled then set active count to prevent device
+ * from restarting because simulator cannot run device restarts
+ */
+ if (val) {
+ /* Check if CFF is on for some other device already */
+ for (i = 0; i < KGSL_DEVICE_MAX; i++) {
+ if (kgsl_driver.devp[i]) {
+ struct kgsl_device *device_temp =
+ kgsl_driver.devp[i];
+ if (device_temp->cff_dump_enable &&
+ device != device_temp) {
+ KGSL_CORE_ERR(
+ "CFF is on for another device %d\n",
+ device_temp->id);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ if (!device->cff_dump_enable) {
+ mutex_lock(&device->mutex);
+ device->cff_dump_enable = 1;
+ ret = kgsl_open_device(device);
+ if (!ret)
+ ret = kgsl_active_count_get(device);
+ if (ret)
+ device->cff_dump_enable = 0;
+ mutex_unlock(&device->mutex);
+ }
+ } else if (device->cff_dump_enable && !val) {
+ mutex_lock(&device->mutex);
+ ret = kgsl_close_device(device);
+ device->cff_dump_enable = 0;
+ mutex_unlock(&device->mutex);
+ }
+done:
+ mutex_unlock(&kgsl_driver.devlock);
+ return ret;
+}
+EXPORT_SYMBOL(kgsl_cff_dump_enable_set);
+
+int kgsl_cff_dump_enable_get(void *data, u64 *val)
+{
+ struct kgsl_device *device = (struct kgsl_device *)data;
+ *val = device->cff_dump_enable;
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_cff_dump_enable_get);
diff --git a/drivers/gpu/msm/kgsl_cffdump.h b/drivers/gpu/msm/kgsl_cffdump.h
index d5656f8..641348e 100644
--- a/drivers/gpu/msm/kgsl_cffdump.h
+++ b/drivers/gpu/msm/kgsl_cffdump.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
@@ -14,6 +14,8 @@
#ifndef __KGSL_CFFDUMP_H
#define __KGSL_CFFDUMP_H
+extern unsigned int kgsl_cff_dump_enable;
+
#ifdef CONFIG_MSM_KGSL_CFF_DUMP
#include <linux/types.h>
@@ -23,46 +25,64 @@
void kgsl_cffdump_init(void);
void kgsl_cffdump_destroy(void);
void kgsl_cffdump_open(struct kgsl_device *device);
-void kgsl_cffdump_close(enum kgsl_deviceid device_id);
+void kgsl_cffdump_close(struct kgsl_device *device);
void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes,
bool clean_cache);
-void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes);
-void kgsl_cffdump_regwrite(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_setmem(struct kgsl_device *device, uint addr,
+ uint value, uint sizebytes);
+void kgsl_cffdump_regwrite(struct kgsl_device *device, uint addr,
uint value);
-void kgsl_cffdump_regpoll(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_regpoll(struct kgsl_device *device, uint addr,
uint value, uint mask);
bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
bool check_only);
-void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
+void kgsl_cffdump_user_event(struct kgsl_device *device,
+ unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5);
static inline bool kgsl_cffdump_flags_no_memzero(void) { return true; }
-void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
+void kgsl_cffdump_memory_base(struct kgsl_device *device, unsigned int base,
unsigned int range, unsigned int gmemsize);
-void kgsl_cffdump_hang(enum kgsl_deviceid device_id);
+void kgsl_cffdump_hang(struct kgsl_device *device);
+int kgsl_cff_dump_enable_set(void *data, u64 val);
+int kgsl_cff_dump_enable_get(void *data, u64 *val);
#else
#define kgsl_cffdump_init() (void)0
#define kgsl_cffdump_destroy() (void)0
#define kgsl_cffdump_open(device) (void)0
-#define kgsl_cffdump_close(device_id) (void)0
+#define kgsl_cffdump_close(device) (void)0
#define kgsl_cffdump_syncmem(dev_priv, memdesc, addr, sizebytes, clean_cache) \
(void) 0
-#define kgsl_cffdump_setmem(addr, value, sizebytes) (void)0
-#define kgsl_cffdump_regwrite(device_id, addr, value) (void)0
-#define kgsl_cffdump_regpoll(device_id, addr, value, mask) (void)0
+#define kgsl_cffdump_setmem(device, addr, value, sizebytes) (void)0
+#define kgsl_cffdump_regwrite(device, addr, value) (void)0
+#define kgsl_cffdump_regpoll(device, addr, value, mask) (void)0
#define kgsl_cffdump_parse_ibs(dev_priv, memdesc, gpuaddr, \
sizedwords, check_only) true
#define kgsl_cffdump_flags_no_memzero() true
-#define kgsl_cffdump_memory_base(base, range, gmemsize) (void)0
-#define kgsl_cffdump_hang(device_id) (void)0
-#define kgsl_cffdump_user_event(cff_opcode, op1, op2, op3, op4, op5) \
- (void)param
+#define kgsl_cffdump_memory_base(davice, base, range, gmemsize) (void)0
+#define kgsl_cffdump_hang(device) (void)0
+static inline void kgsl_cffdump_user_event(struct kgsl_device *device,
+ unsigned int cff_opcode, unsigned int op1,
+ unsigned int op2, unsigned int op3,
+ unsigned int op4, unsigned int op5)
+{
+ return;
+}
+static inline int kgsl_cff_dump_enable_set(void *data, u64 val)
+{
+ return -EINVAL;
+}
+
+static inline int kgsl_cff_dump_enable_get(void *data, u64 *val)
+{
+ return -EINVAL;
+}
#endif /* CONFIG_MSM_KGSL_CFF_DUMP */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 3ee9e4e..6477cbd 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -226,6 +226,7 @@
int pm_ib_enabled;
int reset_counter; /* Track how many GPU core resets have occured */
+ int cff_dump_enable;
};
void kgsl_process_events(struct work_struct *work);
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 6f139b9..68052b1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -359,7 +359,7 @@
int kgsl_gpummu_pt_equal(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base)
+ phys_addr_t pt_base)
{
struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
@@ -458,15 +458,20 @@
if (gpummu_pt->base.hostptr == NULL)
goto err_flushfilter;
+ /* Do a check before truncating phys_addr_t to unsigned 32 */
+ if (sizeof(phys_addr_t) > sizeof(unsigned int)) {
+ WARN_ONCE(1, "Cannot use LPAE with gpummu\n");
+ goto err_flushfilter;
+ }
+ gpummu_pt->base.gpuaddr = gpummu_pt->base.physaddr;
+ gpummu_pt->base.size = KGSL_PAGETABLE_SIZE;
+
/* ptpool allocations are from coherent memory, so update the
device statistics acordingly */
KGSL_STATS_ADD(KGSL_PAGETABLE_SIZE, kgsl_driver.stats.coherent,
kgsl_driver.stats.coherent_max);
- gpummu_pt->base.gpuaddr = gpummu_pt->base.physaddr;
- gpummu_pt->base.size = KGSL_PAGETABLE_SIZE;
-
return (void *)gpummu_pt;
err_flushfilter:
@@ -576,7 +581,7 @@
kgsl_regwrite(device, MH_INTERRUPT_MASK,
GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
mmu->setstate_memory.size);
/* TRAN_ERROR needs a 32 byte (32 byte aligned) chunk of memory
@@ -723,7 +728,7 @@
return 0;
}
-static unsigned int
+static phys_addr_t
kgsl_gpummu_get_current_ptbase(struct kgsl_mmu *mmu)
{
unsigned int ptbase;
@@ -731,7 +736,7 @@
return ptbase;
}
-static unsigned int
+static phys_addr_t
kgsl_gpummu_get_pt_base_addr(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt)
{
@@ -757,7 +762,7 @@
.mmu_get_pt_base_addr = kgsl_gpummu_get_pt_base_addr,
.mmu_enable_clk = NULL,
.mmu_disable_clk_on_ts = NULL,
- .mmu_get_pt_lsb = NULL,
+ .mmu_get_default_ttbr0 = NULL,
.mmu_get_reg_gpuaddr = NULL,
.mmu_get_reg_ahbaddr = NULL,
.mmu_get_num_iommu_units = kgsl_gpummu_get_num_iommu_units,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 513fb90..0bacc5e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -242,7 +242,7 @@
list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (private->pagetable->name != id)
+ if (private->pagetable && (private->pagetable->name != id))
continue;
spin_lock(&private->mem_lock);
@@ -609,11 +609,12 @@
*/
static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base)
+ phys_addr_t pt_base)
{
struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
- unsigned int domain_ptbase = iommu_pt ?
+ phys_addr_t domain_ptbase = iommu_pt ?
iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+
/* Only compare the valid address bits of the pt_base */
domain_ptbase &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
@@ -918,17 +919,17 @@
if (iommu->sync_lock_initialized)
return status;
- iommu_access_ops = get_iommu_access_ops_v0();
+ iommu_access_ops = msm_get_iommu_access_ops();
- if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize)
- lock_phy_addr = (iommu_access_ops->iommu_lock_initialize()
- - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
-
- if (!lock_phy_addr) {
- iommu_access_ops = NULL;
- KGSL_DRV_ERR(mmu->device,
- "GPU CPU sync lock is not supported by kernel\n");
- return -ENXIO;
+ if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize) {
+ lock_phy_addr = (uint32_t)
+ iommu_access_ops->iommu_lock_initialize();
+ if (!lock_phy_addr) {
+ iommu_access_ops = NULL;
+ return status;
+ }
+ lock_phy_addr = lock_phy_addr - (uint32_t)MSM_SHARED_RAM_BASE +
+ (uint32_t)msm_shared_ram_phys;
}
/* Align the physical address to PAGE boundary and store the offset */
@@ -1152,7 +1153,7 @@
* Return - actual pagetable address that the ttbr0 register is programmed
* with
*/
-static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
+static phys_addr_t kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt)
{
struct kgsl_iommu_pt *iommu_pt = pt->priv;
@@ -1161,17 +1162,15 @@
}
/*
- * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
+ * kgsl_iommu_get_default_ttbr0 - Return the ttbr0 value programmed by
+ * iommu driver
* @mmu - Pointer to mmu structure
* @hostptr - Pointer to the IOMMU register map. This is used to match
* the iommu device whose lsb value is to be returned
* @ctx_id - The context bank whose lsb valus is to be returned
- * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
- * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
- * are only programmed once in the beginning when a domain is attached
- * does not change.
+ * Return - returns the ttbr0 value programmed by iommu driver
*/
-static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
+static phys_addr_t kgsl_iommu_get_default_ttbr0(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id)
{
@@ -1182,7 +1181,7 @@
for (j = 0; j < iommu_unit->dev_count; j++)
if (unit_id == i &&
ctx_id == iommu_unit->dev[j].ctx_id)
- return iommu_unit->dev[j].pt_lsb;
+ return iommu_unit->dev[j].default_ttbr0;
}
return 0;
}
@@ -1386,7 +1385,7 @@
/* A nop is required in an indirect buffer when switching
* pagetables in-stream */
- kgsl_sharedmem_writel(&mmu->setstate_memory,
+ kgsl_sharedmem_writel(mmu->device, &mmu->setstate_memory,
KGSL_IOMMU_SETSTATE_NOP_OFFSET,
cp_nop_packet(1));
@@ -1626,18 +1625,26 @@
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
- iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
+ if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
+ iommu_unit->dev[j].default_ttbr0 =
+ KGSL_IOMMU_GET_CTX_REG_LL(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ TTBR0);
+ } else {
+ iommu_unit->dev[j].default_ttbr0 =
KGSL_IOMMU_GET_CTX_REG(iommu,
iommu_unit,
iommu_unit->dev[j].ctx_id,
- TTBR0));
+ TTBR0);
+ }
}
}
kgsl_iommu_lock_rb_in_tlb(mmu);
_iommu_unlock();
/* For complete CFF */
- kgsl_cffdump_setmem(mmu->setstate_memory.gpuaddr +
+ kgsl_cffdump_setmem(mmu->device, mmu->setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET,
cp_nop_packet(1), sizeof(unsigned int));
@@ -1728,10 +1735,36 @@
return ret;
}
-static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
+void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu)
{
struct kgsl_iommu *iommu = mmu->priv;
int i, j;
+
+ if (mmu->fault) {
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit =
+ &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++) {
+ if (iommu_unit->dev[j].fault) {
+ kgsl_iommu_enable_clk(mmu, j);
+ _iommu_lock();
+ KGSL_IOMMU_SET_CTX_REG(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ RESUME, 1);
+ _iommu_unlock();
+ iommu_unit->dev[j].fault = 0;
+ }
+ }
+ }
+ mmu->fault = 0;
+ }
+}
+
+
+static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
/*
* stop device mmu
*
@@ -1744,25 +1777,7 @@
mmu->flags &= ~KGSL_FLAGS_STARTED;
- if (mmu->fault) {
- for (i = 0; i < iommu->unit_count; i++) {
- struct kgsl_iommu_unit *iommu_unit =
- &iommu->iommu_units[i];
- for (j = 0; j < iommu_unit->dev_count; j++) {
- if (iommu_unit->dev[j].fault) {
- kgsl_iommu_enable_clk(mmu, j);
- _iommu_lock();
- KGSL_IOMMU_SET_CTX_REG(iommu,
- iommu_unit,
- iommu_unit->dev[j].ctx_id,
- RESUME, 1);
- _iommu_unlock();
- iommu_unit->dev[j].fault = 0;
- }
- }
- }
- mmu->fault = 0;
- }
+ kgsl_iommu_pagefault_resume(mmu);
}
/* switch off MMU clocks and cancel any events it has queued */
iommu->clk_event_queued = false;
@@ -1806,10 +1821,10 @@
return 0;
}
-static unsigned int
+static phys_addr_t
kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
{
- unsigned int pt_base;
+ phys_addr_t pt_base;
struct kgsl_iommu *iommu = mmu->priv;
/* We cannot enable or disable the clocks in interrupt context, this
function is called from interrupt context if there is an axi error */
@@ -1842,16 +1857,14 @@
struct kgsl_iommu *iommu = mmu->priv;
int temp;
int i;
- unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
+ phys_addr_t pt_base = kgsl_iommu_get_pt_base_addr(mmu,
mmu->hwpagetable);
- unsigned int pt_val;
+ phys_addr_t pt_val;
if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
return;
}
- /* Mask off the lsb of the pt base address since lsb will not change */
- pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
/* For v0 SMMU GPU needs to be idle for tlb invalidate as well */
if (msm_soc_version_supports_iommu_v0())
@@ -1866,12 +1879,21 @@
for (i = 0; i < iommu->unit_count; i++) {
/* get the lsb value which should not change when
* changing ttbr0 */
- pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
+ pt_val = kgsl_iommu_get_default_ttbr0(mmu, i,
KGSL_IOMMU_CONTEXT_USER);
- pt_val += pt_base;
- KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
- KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+ pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ pt_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ pt_val |= pt_base;
+ if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
+ KGSL_IOMMU_SET_CTX_REG_LL(iommu,
+ (&iommu->iommu_units[i]),
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+ } else {
+ KGSL_IOMMU_SET_CTX_REG(iommu,
+ (&iommu->iommu_units[i]),
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+ }
mb();
temp = KGSL_IOMMU_GET_CTX_REG(iommu,
@@ -1973,10 +1995,11 @@
.mmu_setstate = kgsl_iommu_setstate,
.mmu_device_setstate = kgsl_iommu_default_setstate,
.mmu_pagefault = NULL,
+ .mmu_pagefault_resume = kgsl_iommu_pagefault_resume,
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
- .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
+ .mmu_get_default_ttbr0 = kgsl_iommu_get_default_ttbr0,
.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
.mmu_get_reg_ahbaddr = kgsl_iommu_get_reg_ahbaddr,
.mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index b1b83c0..5c4b17e 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -47,7 +47,12 @@
#define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT 4
/* TTBR0 register fields */
+#ifdef CONFIG_ARM_LPAE
+#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK_LPAE 0x000000FFFFFFFFE0ULL
+#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK KGSL_IOMMU_CTX_TTBR0_ADDR_MASK_LPAE
+#else
#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK 0xFFFFC000
+#endif
/* TLBSTATUS register fields */
#define KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE BIT(0)
@@ -78,20 +83,6 @@
int ctx_reg;
};
-#ifdef CONFIG_MSM_IOMMU
-extern struct iommu_access_ops iommu_access_ops_v0;
-
-static inline struct iommu_access_ops *get_iommu_access_ops_v0(void)
-{
- return &iommu_access_ops_v0;
-}
-#else
-static inline struct iommu_access_ops *get_iommu_access_ops_v0(void)
-{
- return NULL;
-}
-#endif
-
/*
* Max number of iommu units that the gpu core can have
* On APQ8064, KGSL can control a maximum of 2 IOMMU units.
@@ -102,6 +93,20 @@
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
/* Macros to read/write IOMMU registers */
+#define KGSL_IOMMU_SET_CTX_REG_LL(iommu, iommu_unit, ctx, REG, val) \
+ writell_relaxed(val, \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
+
+#define KGSL_IOMMU_GET_CTX_REG_LL(iommu, iommu_unit, ctx, REG) \
+ readl_relaxed( \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
+
#define KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, ctx, REG, val) \
writel_relaxed(val, \
iommu_unit->reg_map.hostptr + \
@@ -128,8 +133,7 @@
* @dev: Device pointer to iommu context
* @attached: Indicates whether this iommu context is presently attached to
* a pagetable/domain or not
- * @pt_lsb: The LSB of IOMMU_TTBR0 register which is the pagetable
- * register
+ * @default_ttbr0: The TTBR0 value set by iommu driver on start up
* @ctx_id: This iommu units context id. It can be either 0 or 1
* @clk_enabled: If set indicates that iommu clocks of this iommu context
* are on, else the clocks are off
@@ -139,7 +143,7 @@
struct kgsl_iommu_device {
struct device *dev;
bool attached;
- unsigned int pt_lsb;
+ phys_addr_t default_ttbr0;
enum kgsl_iommu_context_id ctx_id;
bool clk_enabled;
struct kgsl_device *kgsldev;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 3ebfdcd..12a4b25 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -314,7 +314,7 @@
}
int
-kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base)
+kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, phys_addr_t pt_base)
{
struct kgsl_pagetable *pt;
int ptid = -1;
@@ -335,7 +335,7 @@
EXPORT_SYMBOL(kgsl_mmu_get_ptname_from_ptbase);
unsigned int
-kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, unsigned int pt_base,
+kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, phys_addr_t pt_base,
unsigned int addr)
{
struct kgsl_pagetable *pt;
@@ -372,7 +372,7 @@
status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
if (status)
return status;
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
mmu->setstate_memory.size);
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
@@ -410,7 +410,8 @@
static void mh_axi_error(struct kgsl_device *device, const char* type)
{
- unsigned int reg, gpu_err, phys_err, pt_base;
+ unsigned int reg, gpu_err, phys_err;
+ phys_addr_t pt_base;
kgsl_regread(device, MH_AXI_ERROR, ®);
pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
@@ -423,8 +424,8 @@
kgsl_regwrite(device, MH_DEBUG_CTRL, 45);
kgsl_regread(device, MH_DEBUG_DATA, &phys_err);
KGSL_MEM_CRIT(device,
- "axi %s error: %08x pt %08x gpu %08x phys %08x\n",
- type, reg, pt_base, gpu_err, phys_err);
+ "axi %s error: %08x pt %pa gpu %08x phys %08x\n",
+ type, reg, &pt_base, gpu_err, phys_err);
}
void kgsl_mh_intrcallback(struct kgsl_device *device)
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 02cde94..27cfc40 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -139,13 +139,15 @@
void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
uint32_t flags);
void (*mmu_pagefault) (struct kgsl_mmu *mmu);
- unsigned int (*mmu_get_current_ptbase)
+ phys_addr_t (*mmu_get_current_ptbase)
+ (struct kgsl_mmu *mmu);
+ void (*mmu_pagefault_resume)
(struct kgsl_mmu *mmu);
void (*mmu_disable_clk_on_ts)
(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
int (*mmu_enable_clk)
(struct kgsl_mmu *mmu, int ctx_id);
- int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
+ phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id);
unsigned int (*mmu_get_reg_gpuaddr)(struct kgsl_mmu *mmu,
@@ -156,8 +158,8 @@
int (*mmu_get_num_iommu_units)(struct kgsl_mmu *mmu);
int (*mmu_pt_equal) (struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base);
- unsigned int (*mmu_get_pt_base_addr)
+ phys_addr_t pt_base);
+ phys_addr_t (*mmu_get_pt_base_addr)
(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt);
int (*mmu_setup_pt) (struct kgsl_mmu *mmu,
@@ -228,9 +230,9 @@
void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
uint32_t flags);
int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
- unsigned int pt_base);
+ phys_addr_t pt_base);
unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu,
- unsigned int pt_base, unsigned int addr);
+ phys_addr_t pt_base, unsigned int addr);
int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
enum kgsl_deviceid id);
void kgsl_mmu_ptpool_destroy(void *ptpool);
@@ -246,7 +248,7 @@
* of as wrappers around the actual function
*/
-static inline unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_mmu *mmu)
+static inline phys_addr_t kgsl_mmu_get_current_ptbase(struct kgsl_mmu *mmu)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_current_ptbase)
return mmu->mmu_ops->mmu_get_current_ptbase(mmu);
@@ -277,7 +279,7 @@
static inline int kgsl_mmu_pt_equal(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base)
+ phys_addr_t pt_base)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_pt_equal)
return mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base);
@@ -285,7 +287,7 @@
return 1;
}
-static inline unsigned int kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
+static inline phys_addr_t kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_base_addr)
@@ -294,12 +296,13 @@
return 0;
}
-static inline int kgsl_mmu_get_pt_lsb(struct kgsl_mmu *mmu,
+static inline phys_addr_t kgsl_mmu_get_default_ttbr0(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id)
{
- if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_lsb)
- return mmu->mmu_ops->mmu_get_pt_lsb(mmu, unit_id, ctx_id);
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_default_ttbr0)
+ return mmu->mmu_ops->mmu_get_default_ttbr0(mmu, unit_id,
+ ctx_id);
else
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 05d24e9..847c59e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -482,49 +482,6 @@
pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
}
-static int kgsl_pwrctrl_pwrnap_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- char temp[20];
- unsigned long val;
- struct kgsl_device *device = kgsl_device_from_dev(dev);
- struct kgsl_pwrctrl *pwr;
- int rc;
-
- if (device == NULL)
- return 0;
- pwr = &device->pwrctrl;
-
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = strict_strtoul(temp, 0, &val);
- if (rc)
- return rc;
-
- mutex_lock(&device->mutex);
-
- if (val == 1)
- pwr->nap_allowed = true;
- else if (val == 0)
- pwr->nap_allowed = false;
-
- mutex_unlock(&device->mutex);
-
- return count;
-}
-
-static int kgsl_pwrctrl_pwrnap_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct kgsl_device *device = kgsl_device_from_dev(dev);
- if (device == NULL)
- return 0;
- return snprintf(buf, PAGE_SIZE, "%d\n", device->pwrctrl.nap_allowed);
-}
-
-
static int kgsl_pwrctrl_idle_timer_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -759,7 +716,6 @@
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);
-DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
kgsl_pwrctrl_idle_timer_store);
DEVICE_ATTR(gpubusy, 0444, kgsl_pwrctrl_gpubusy_show,
@@ -797,7 +753,6 @@
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
&dev_attr_max_gpuclk,
- &dev_attr_pwrnap,
&dev_attr_idle_timer,
&dev_attr_gpubusy,
&dev_attr_gputop,
@@ -1061,6 +1016,7 @@
pwr->active_pwrlevel = pdata->init_level;
pwr->default_pwrlevel = pdata->init_level;
+ pwr->init_pwrlevel = pdata->init_level;
for (i = 0; i < pdata->num_levels; i++) {
pwr->pwrlevels[i].gpu_freq =
(pdata->pwrlevel[i].gpu_freq > 0) ?
@@ -1090,7 +1046,6 @@
pwr->power_flags = 0;
- pwr->nap_allowed = pdata->nap_allowed;
pwr->idle_needed = pdata->idle_needed;
pwr->interval_timeout = pdata->idle_timeout;
pwr->strtstp_sleepwake = pdata->strtstp_sleepwake;
@@ -1466,8 +1421,10 @@
void kgsl_pwrctrl_enable(struct kgsl_device *device)
{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->default_pwrlevel);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
}
@@ -1615,9 +1572,8 @@
INIT_COMPLETION(device->suspend_gate);
- if (device->pwrctrl.nap_allowed == true &&
- (device->state == KGSL_STATE_ACTIVE &&
- device->requested_state == KGSL_STATE_NONE)) {
+ if (device->state == KGSL_STATE_ACTIVE &&
+ device->requested_state == KGSL_STATE_NONE) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
if (kgsl_pwrctrl_sleep(device) && device->pwrctrl.irq_last) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 7bc849d..3bf65ee 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -23,6 +23,8 @@
#define KGSL_PWRLEVEL_NOMINAL 1
#define KGSL_PWRLEVEL_LAST_OFFSET 2
+#define KGSL_PWR_ON 0xFFFF
+
#define KGSL_MAX_CLKS 6
struct platform_device;
@@ -47,6 +49,8 @@
* @pwrlevels - List of supported power levels
* @active_pwrlevel - The currently active power level
* @thermal_pwrlevel - maximum powerlevel constraint from thermal
+ * @default_pwrlevel - device wake up power level
+ * @init_pwrlevel - device inital power level
* @max_pwrlevel - maximum allowable powerlevel per the user
* @min_pwrlevel - minimum allowable powerlevel per the user
* @num_pwrlevels - number of available power levels
@@ -55,7 +59,6 @@
* @gpu_reg - pointer to the regulator structure for gpu_reg
* @gpu_cx - pointer to the regulator structure for gpu_cx
* @pcl - bus scale identifier
- * @nap_allowed - true if the device supports naps
* @idle_needed - true if the device needs a idle before clock change
* @irq_name - resource name for the IRQ
* @clk_stats - structure of clock statistics
@@ -74,6 +77,7 @@
unsigned int active_pwrlevel;
int thermal_pwrlevel;
unsigned int default_pwrlevel;
+ unsigned int init_pwrlevel;
unsigned int max_pwrlevel;
unsigned int min_pwrlevel;
unsigned int num_pwrlevels;
@@ -82,7 +86,6 @@
struct regulator *gpu_reg;
struct regulator *gpu_cx;
uint32_t pcl;
- unsigned int nap_allowed;
unsigned int idle_needed;
const char *irq_name;
s64 time;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index afef62e..e5e23f0 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -306,6 +306,8 @@
kgsl_pwrctrl_pwrlevel_change(device,
device->pwrctrl.max_pwrlevel);
+ device->pwrctrl.default_pwrlevel =
+ device->pwrctrl.max_pwrlevel;
}
device->pwrscale.policy = NULL;
}
@@ -338,6 +340,8 @@
device->pwrscale.policy = policy;
+ device->pwrctrl.default_pwrlevel =
+ device->pwrctrl.init_pwrlevel;
/* Pwrscale is enabled by default at attach time */
kgsl_pwrscale_enable(device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 5d5d5b1..cfc409c 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -110,8 +110,12 @@
else if (!strncmp(str, "performance", 11))
priv->governor = TZ_GOVERNOR_PERFORMANCE;
- if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
+ if (priv->governor == TZ_GOVERNOR_PERFORMANCE) {
kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+ pwr->default_pwrlevel = pwr->max_pwrlevel;
+ } else {
+ pwr->default_pwrlevel = pwr->init_pwrlevel;
+ }
mutex_unlock(&device->mutex);
return count;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 4071b37..01f0768 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
};
@@ -852,7 +879,8 @@
EXPORT_SYMBOL(kgsl_sharedmem_readl);
int
-kgsl_sharedmem_writel(const struct kgsl_memdesc *memdesc,
+kgsl_sharedmem_writel(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc,
unsigned int offsetbytes,
uint32_t src)
{
@@ -865,7 +893,8 @@
WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size);
if (offsetbytes + sizeof(uint32_t) > memdesc->size)
return -ERANGE;
- kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes,
+ kgsl_cffdump_setmem(device,
+ memdesc->gpuaddr + offsetbytes,
src, sizeof(uint32_t));
dst = (uint32_t *)(memdesc->hostptr + offsetbytes);
*dst = src;
@@ -874,14 +903,16 @@
EXPORT_SYMBOL(kgsl_sharedmem_writel);
int
-kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
- unsigned int value, unsigned int sizebytes)
+kgsl_sharedmem_set(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
+ unsigned int value, unsigned int sizebytes)
{
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
BUG_ON(offsetbytes + sizebytes > memdesc->size);
- kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes, value,
- sizebytes);
+ kgsl_cffdump_setmem(device,
+ memdesc->gpuaddr + offsetbytes, value,
+ sizebytes);
memset(memdesc->hostptr + offsetbytes, value, sizebytes);
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 14ae0dc..985b9b8 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -55,11 +55,13 @@
uint32_t *dst,
unsigned int offsetbytes);
-int kgsl_sharedmem_writel(const struct kgsl_memdesc *memdesc,
+int kgsl_sharedmem_writel(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc,
unsigned int offsetbytes,
uint32_t src);
-int kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc,
+int kgsl_sharedmem_set(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc,
unsigned int offsetbytes, unsigned int value,
unsigned int sizebytes);
@@ -154,7 +156,7 @@
static inline int
memdesc_sg_phys(struct kgsl_memdesc *memdesc,
- unsigned int physaddr, unsigned int size)
+ phys_addr_t physaddr, unsigned int size)
{
memdesc->sg = kgsl_sg_alloc(1);
if (memdesc->sg == NULL)
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 6fcd912..d3edbba 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -27,7 +27,7 @@
struct kgsl_snapshot_object {
unsigned int gpuaddr;
- unsigned int ptbase;
+ phys_addr_t ptbase;
unsigned int size;
unsigned int offset;
int type;
@@ -140,6 +140,7 @@
int hang = (int) priv;
int ctxtcount = 0;
int size = sizeof(*header);
+ phys_addr_t temp_ptbase;
/* Figure out how many active contexts there are - these will
* be appended on the end of the structure */
@@ -181,11 +182,14 @@
kgsl_sharedmem_readl(&device->memstore, &header->current_context,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
+
/* Get the current PT base */
- header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
+ temp_ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
+ /* Truncate to 32 bits in case LPAE is used */
+ header->ptbase = (__u32)temp_ptbase;
/* And the PID for the task leader */
pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
- header->ptbase);
+ temp_ptbase);
task = find_task_by_vpid(pid);
@@ -267,7 +271,7 @@
header.size = ALIGN(obj->size, 4) >> 2;
header.gpuaddr = obj->gpuaddr;
- header.ptbase = obj->ptbase;
+ header.ptbase = (__u32)obj->ptbase;
header.type = obj->type;
ret = obj_itr_out(itr, &header, sizeof(header));
@@ -309,7 +313,7 @@
* Return 1 if the object is already in the list - this can save us from
* having to parse the sme thing over again.
*/
-int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_have_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size)
{
struct kgsl_snapshot_object *obj;
@@ -339,7 +343,7 @@
* size of the object being frozen
*/
-int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_get_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size, unsigned int type)
{
struct kgsl_mem_entry *entry;
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 4db2815..61a3b22 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -320,10 +320,10 @@
unsigned int data, unsigned int start, unsigned int count);
/* Freeze a GPU buffer so it can be dumped in the snapshot */
-int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_get_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size, unsigned int type);
-int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_have_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size);
#endif
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index aad8ef1..2f67405 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -12,9 +12,12 @@
*/
#include <linux/file.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <asm/current.h>
+
#include "kgsl_sync.h"
struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
@@ -179,24 +182,67 @@
return ret;
}
+static unsigned int kgsl_sync_get_timestamp(
+ struct kgsl_sync_timeline *ktimeline, enum kgsl_timestamp_type type)
+{
+ struct kgsl_context *context = idr_find(&ktimeline->device->context_idr,
+ ktimeline->context_id);
+ if (context == NULL)
+ return 0;
+
+ return kgsl_readtimestamp(ktimeline->device, context, type);
+}
+
+static void kgsl_sync_timeline_value_str(struct sync_timeline *sync_timeline,
+ char *str, int size)
+{
+ struct kgsl_sync_timeline *ktimeline =
+ (struct kgsl_sync_timeline *) sync_timeline;
+ unsigned int timestamp_retired = kgsl_sync_get_timestamp(ktimeline,
+ KGSL_TIMESTAMP_RETIRED);
+ snprintf(str, size, "%u retired:%u", ktimeline->last_timestamp,
+ timestamp_retired);
+}
+
+static void kgsl_sync_pt_value_str(struct sync_pt *sync_pt,
+ char *str, int size)
+{
+ struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) sync_pt;
+ snprintf(str, size, "%u", kpt->timestamp);
+}
+
static const struct sync_timeline_ops kgsl_sync_timeline_ops = {
.driver_name = "kgsl-timeline",
.dup = kgsl_sync_pt_dup,
.has_signaled = kgsl_sync_pt_has_signaled,
.compare = kgsl_sync_pt_compare,
+ .timeline_value_str = kgsl_sync_timeline_value_str,
+ .pt_value_str = kgsl_sync_pt_value_str,
};
int kgsl_sync_timeline_create(struct kgsl_context *context)
{
struct kgsl_sync_timeline *ktimeline;
+ /* Generate a name which includes the thread name, thread id, process
+ * name, process id, and context id. This makes it possible to
+ * identify the context of a timeline in the sync dump. */
+ char ktimeline_name[sizeof(context->timeline->name)] = {};
+ snprintf(ktimeline_name, sizeof(ktimeline_name),
+ "%s_%.15s(%d)-%.15s(%d)-%d",
+ context->dev_priv->device->name,
+ current->group_leader->comm, current->group_leader->pid,
+ current->comm, current->pid, context->id);
+
context->timeline = sync_timeline_create(&kgsl_sync_timeline_ops,
- (int) sizeof(struct kgsl_sync_timeline), "kgsl-timeline");
+ (int) sizeof(struct kgsl_sync_timeline), ktimeline_name);
if (context->timeline == NULL)
return -EINVAL;
ktimeline = (struct kgsl_sync_timeline *) context->timeline;
ktimeline->last_timestamp = 0;
+ ktimeline->device = context->dev_priv->device;
+ ktimeline->context_id = context->id;
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 06b3ad0..63adf06 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -19,6 +19,8 @@
struct kgsl_sync_timeline {
struct sync_timeline timeline;
unsigned int last_timestamp;
+ struct kgsl_device *device;
+ u32 context_id;
};
struct kgsl_sync_pt {
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 08677ef..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,
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 49265fc..78e2859 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -216,8 +216,7 @@
}
}
- if ((device->pwrctrl.nap_allowed == true) &&
- (device->requested_state == KGSL_STATE_NONE)) {
+ if (device->requested_state == KGSL_STATE_NONE) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
queue_work(device->work_queue, &device->idle_check_ws);
}
@@ -467,10 +466,10 @@
addmarker(&z180_dev->ringbuffer, z180_dev->current_timestamp);
/* monkey patch the IB so that it jumps back to the ringbuffer */
- kgsl_sharedmem_writel(&entry->memdesc,
+ kgsl_sharedmem_writel(device, &entry->memdesc,
((sizedwords + 1) * sizeof(unsigned int)),
rb_gpuaddr(z180_dev, z180_dev->current_timestamp));
- kgsl_sharedmem_writel(&entry->memdesc,
+ kgsl_sharedmem_writel(device, &entry->memdesc,
((sizedwords + 2) * sizeof(unsigned int)),
nextcnt);
@@ -710,7 +709,7 @@
BUG_ON(offsetwords*sizeof(uint32_t) >= device->reg_len);
reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
- kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
+ kgsl_cffdump_regwrite(device, offsetwords << 2, value);
/*ensure previous writes post before this one,
* i.e. act like normal writel() */
wmb();
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index 55b8faa..5d929cf 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -118,7 +118,7 @@
int rb_slot_num = -1;
struct z180_device *z180_dev = Z180_DEVICE(device);
struct kgsl_mem_entry *entry = NULL;
- unsigned int pt_base;
+ phys_addr_t pt_base;
unsigned int i;
unsigned int j;
char linebuf[CHARS_PER_LINE];
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
index 3a16bb7..ef0e083 100644
--- a/drivers/gud/Makefile
+++ b/drivers/gud/Makefile
@@ -10,7 +10,8 @@
mobicore_driver/ops.o \
mobicore_driver/mem.o \
mobicore_driver/api.o \
- mobicore_driver/main.o
+ mobicore_driver/main.o \
+ mobicore_driver/pm.o
mckernelapi-objs := mobicore_kernelapi/main.o \
mobicore_kernelapi/clientlib.o \
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
index 4abd003..2a7772e 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -26,4 +26,4 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define MOBICORE_COMPONENT_BUILD_TAG \
- "*** GC_MSM8960_Release_V016 ###"
+ "*** GC_MSM8960_Release_V019 ###"
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index a2b3ad7..6f91974 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -29,6 +29,7 @@
#include <linux/mman.h>
#include <linux/completion.h>
#include <linux/fdtable.h>
+#include <linux/cdev.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/tcp_states.h>
@@ -50,12 +51,20 @@
};
struct device mcd_debug_subname = {
- .init_name = "", /* Set to 'mcd' at mc_init() time */
.driver = &mcd_debug_name
};
struct device *mcd = &mcd_debug_subname;
+/* We need 2 devices for admin and user interface*/
+#define MC_DEV_MAX 2
+
+/* Need to discover a chrdev region for the driver */
+static dev_t mc_dev_admin, mc_dev_user;
+struct cdev mc_admin_cdev, mc_user_cdev;
+/* Device class for the driver assigned major */
+static struct class *mc_device_class;
+
#ifndef FMODE_PATH
#define FMODE_PATH 0x0
#endif
@@ -1205,13 +1214,6 @@
.read = mc_fd_read,
};
-static struct miscdevice mc_admin_device = {
- .name = MC_ADMIN_DEVNODE,
- .mode = (S_IRWXU),
- .minor = 253,
- .fops = &mc_admin_fops,
-};
-
/* function table structure of this device driver. */
static const struct file_operations mc_user_fops = {
.owner = THIS_MODULE,
@@ -1221,30 +1223,80 @@
.mmap = mc_fd_mmap,
};
-static struct miscdevice mc_user_device = {
- .name = MC_USER_DEVNODE,
- .mode = (S_IRWXU | S_IRWXG | S_IRWXO),
- .minor = 254,
- .fops = &mc_user_fops,
-};
+static int create_devices(void)
+{
+ int ret = 0;
+
+ cdev_init(&mc_admin_cdev, &mc_admin_fops);
+ cdev_init(&mc_user_cdev, &mc_user_fops);
+
+ mc_device_class = class_create(THIS_MODULE, "mobicore");
+ if (IS_ERR(mc_device_class)) {
+ MCDRV_DBG_ERROR(mcd, "failed to create device class");
+ ret = PTR_ERR(mc_device_class);
+ goto out;
+ }
+
+ ret = alloc_chrdev_region(&mc_dev_admin, 0, MC_DEV_MAX, "mobicore");
+ if (ret < 0) {
+ MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region\n");
+ goto error;
+ }
+ mc_dev_user = MKDEV(MAJOR(mc_dev_admin), 1);
+
+ MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_region));
+
+ /* First the ADMIN node */
+ ret = cdev_add(&mc_admin_cdev, mc_dev_admin, 1);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "admin device register failed\n");
+ goto error;
+ }
+ mc_admin_cdev.owner = THIS_MODULE;
+ device_create(mc_device_class, NULL, mc_dev_admin, NULL,
+ MC_ADMIN_DEVNODE);
+
+ /* Then the user node */
+
+ ret = cdev_add(&mc_user_cdev, mc_dev_user, 1);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "user device register failed\n");
+ goto error_unregister;
+ }
+ mc_user_cdev.owner = THIS_MODULE;
+ device_create(mc_device_class, NULL, mc_dev_user, NULL,
+ MC_USER_DEVNODE);
+
+ goto out;
+error_unregister:
+ device_destroy(mc_device_class, mc_dev_admin);
+ device_destroy(mc_device_class, mc_dev_user);
+
+ cdev_del(&mc_admin_cdev);
+ cdev_del(&mc_user_cdev);
+ unregister_chrdev_region(mc_dev_admin, MC_DEV_MAX);
+error:
+ class_destroy(mc_device_class);
+out:
+ return ret;
+}
/*
* This function is called the kernel during startup or by a insmod command.
- * This device is installed and registered as miscdevice, then interrupt and
+ * This device is installed and registered as cdev, then interrupt and
* queue handling is set up
*/
static int __init mobicore_init(void)
{
int ret = 0;
-
dev_set_name(mcd, "mcd");
- MCDRV_DBG(mcd, "enter (Build " __TIMESTAMP__ ")\n");
- MCDRV_DBG(mcd, "mcDrvModuleApi version is %i.%i\n",
- MCDRVMODULEAPI_VERSION_MAJOR,
- MCDRVMODULEAPI_VERSION_MINOR);
+ dev_info(mcd, "MobiCore Driver, Build: " __TIMESTAMP__ "\n");
+ dev_info(mcd, "MobiCore mcDrvModuleApi version is %i.%i\n",
+ MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
#ifdef MOBICORE_COMPONENT_BUILD_TAG
- MCDRV_DBG(mcd, "%s\n", MOBICORE_COMPONENT_BUILD_TAG);
+ dev_info(mcd, "MobiCore %s\n", MOBICORE_COMPONENT_BUILD_TAG);
#endif
/* Hardware does not support ARM TrustZone -> Cannot continue! */
if (!has_security_extensions()) {
@@ -1264,6 +1316,10 @@
goto error;
init_completion(&ctx.isr_comp);
+
+ /* initialize event counter for signaling of an IRQ to zero */
+ atomic_set(&ctx.isr_counter, 0);
+
/* set up S-SIQ interrupt handler */
ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
MC_ADMIN_DEVNODE, &ctx);
@@ -1280,23 +1336,16 @@
}
#endif
- ret = misc_register(&mc_admin_device);
- if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "admin device register failed\n");
- goto free_isr;
- }
-
- ret = misc_register(&mc_user_device);
- if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "user device register failed\n");
- goto free_admin;
- }
-
- /* initialize event counter for signaling of an IRQ to zero */
- atomic_set(&ctx.isr_counter, 0);
+ ret = create_devices();
+ if (ret != 0)
+ goto free_pm;
ret = mc_init_l2_tables();
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ ret = mc_pm_clock_initialize();
+#endif
+
/*
* initialize unique number counter which we can use for
* handles. It is limited to 2^32, but this should be
@@ -1315,10 +1364,12 @@
MCDRV_DBG(mcd, "initialized\n");
return 0;
-free_admin:
- misc_deregister(&mc_admin_device);
+free_pm:
+#ifdef MC_PM_RUNTIME
+ mc_pm_free();
free_isr:
free_irq(MC_INTR_SSIQ, &ctx);
+#endif
err_req_irq:
mc_fastcall_destroy();
error:
@@ -1341,13 +1392,19 @@
mc_pm_free();
#endif
+ device_destroy(mc_device_class, mc_dev_admin);
+ device_destroy(mc_device_class, mc_dev_user);
+ class_destroy(mc_device_class);
+ unregister_chrdev_region(mc_dev_admin, MC_DEV_MAX);
+
free_irq(MC_INTR_SSIQ, &ctx);
- misc_deregister(&mc_admin_device);
- misc_deregister(&mc_user_device);
-
mc_fastcall_destroy();
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_finalize();
+#endif
+
MCDRV_DBG_VERBOSE(mcd, "exit");
}
@@ -1358,4 +1415,3 @@
MODULE_AUTHOR("Trustonic Limited");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MobiCore driver");
-
diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c
index 05c80b7..9d4af72 100644
--- a/drivers/gud/mobicore_driver/ops.c
+++ b/drivers/gud/mobicore_driver/ops.c
@@ -60,7 +60,16 @@
{
struct fastcall_work *fc_work =
container_of(work, struct fastcall_work, work);
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_enable();
+#endif
+
smc(fc_work->data);
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_disable();
+#endif
}
void mc_fastcall(void *data)
@@ -114,7 +123,16 @@
{
struct fastcall_work_struct *fc_work =
container_of(work, struct fastcall_work_struct, work);
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_enable();
+#endif
+
smc(fc_work->data);
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_disable();
+#endif
}
void mc_fastcall(void *data)
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
index 7febcb6..4768f39 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -43,4 +43,7 @@
*/
#define MC_VM_UNMAP
+/* Enable Power Management for Crypto Engine */
+#define MC_CRYPTO_CLOCK_MANAGEMENT
+
#endif /* _MC_PLATFORM_H_ */
diff --git a/drivers/gud/mobicore_driver/pm.c b/drivers/gud/mobicore_driver/pm.c
new file mode 100644
index 0000000..3ad2015
--- /dev/null
+++ b/drivers/gud/mobicore_driver/pm.c
@@ -0,0 +1,295 @@
+/*
+ * MobiCore Driver Kernel Module.
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/suspend.h>
+#include <linux/device.h>
+
+#include "main.h"
+#include "pm.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "logging.h"
+#include "debug.h"
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ #include <linux/clk.h>
+ #include <linux/err.h>
+
+ struct clk *mc_ce_iface_clk = NULL;
+ struct clk *mc_ce_core_clk = NULL;
+ struct clk *mc_ce_bus_clk = NULL;
+#endif /* MC_CRYPTO_CLOCK_MANAGEMENT */
+
+#ifdef MC_PM_RUNTIME
+
+static struct mc_context *ctx;
+
+static bool sleep_ready(void)
+{
+ if (!ctx->mcp)
+ return false;
+
+ if (!ctx->mcp->flags.sleep_mode.ReadyToSleep & READY_TO_SLEEP)
+ return false;
+
+ return true;
+}
+
+static void mc_suspend_handler(struct work_struct *work)
+{
+ if (!ctx->mcp)
+ return;
+
+ ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ _nsiq();
+}
+DECLARE_WORK(suspend_work, mc_suspend_handler);
+
+static inline void dump_sleep_params(struct mc_flags *flags)
+{
+ MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule);
+ MCDRV_DBG(mcd,
+ "MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
+ MCDRV_DBG(mcd, "MobiCore Sleep Ready=%d!",
+ flags->sleep_mode.ReadyToSleep);
+}
+
+static int mc_suspend_notifier(struct notifier_block *nb,
+ unsigned long event, void *dummy)
+{
+ struct mc_mcp_buffer *mcp = ctx->mcp;
+ /* We have noting to say if MobiCore is not initialized */
+ if (!mcp)
+ return 0;
+
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
+#endif
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ /*
+ * Make sure we have finished all the work otherwise
+ * we end up in a race condition
+ */
+ cancel_work_sync(&suspend_work);
+ /*
+ * We can't go to sleep if MobiCore is not IDLE
+ * or not Ready to sleep
+ */
+ dump_sleep_params(&mcp->flags);
+ if (!sleep_ready()) {
+ ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ schedule_work_on(0, &suspend_work);
+ flush_work(&suspend_work);
+ if (!sleep_ready()) {
+ dump_sleep_params(&mcp->flags);
+ ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ MCDRV_DBG_ERROR(mcd, "MobiCore can't SLEEP!");
+ return NOTIFY_BAD;
+ }
+ }
+ break;
+ case PM_POST_SUSPEND:
+ MCDRV_DBG(mcd, "Resume MobiCore system!");
+ ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block mc_notif_block = {
+ .notifier_call = mc_suspend_notifier,
+};
+
+#ifdef MC_BL_NOTIFIER
+
+static int bL_switcher_notifier_handler(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ unsigned int mpidr, cpu, cluster;
+ struct mc_mcp_buffer *mcp = ctx->mcp;
+
+ if (!mcp)
+ return 0;
+
+ asm volatile ("mrc\tp15, 0, %0, c0, c0, 5" : "=r" (mpidr));
+ cpu = mpidr & 0x3;
+ cluster = (mpidr >> 8) & 0xf;
+ MCDRV_DBG(mcd, "%s switching!!, cpu: %u, Out=%u\n",
+ (event == SWITCH_ENTER ? "Before" : "After"), cpu, cluster);
+
+ if (cpu != 0)
+ return 0;
+
+ switch (event) {
+ case SWITCH_ENTER:
+ if (!sleep_ready()) {
+ ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ _nsiq();
+ /* By this time we should be ready for sleep or we are
+ * in the middle of something important */
+ if (!sleep_ready()) {
+ dump_sleep_params(&mcp->flags);
+ MCDRV_DBG(mcd,
+ "MobiCore: Don't allow switch!\n");
+ ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ return -EPERM;
+ }
+ }
+ break;
+ case SWITCH_EXIT:
+ ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ break;
+ default:
+ MCDRV_DBG(mcd, "MobiCore: Unknown switch event!\n");
+ }
+
+ return 0;
+}
+
+static struct notifier_block switcher_nb = {
+ .notifier_call = bL_switcher_notifier_handler,
+};
+#endif
+
+int mc_pm_initialize(struct mc_context *context)
+{
+ int ret = 0;
+
+ ctx = context;
+
+ ret = register_pm_notifier(&mc_notif_block);
+ if (ret)
+ MCDRV_DBG_ERROR(mcd, "device pm register failed\n");
+#ifdef MC_BL_NOTIFIER
+ if (register_bL_swicher_notifier(&switcher_nb))
+ MCDRV_DBG_ERROR(mcd,
+ "Failed to register to bL_switcher_notifier\n");
+#endif
+
+ return ret;
+}
+
+int mc_pm_free(void)
+{
+ int ret = unregister_pm_notifier(&mc_notif_block);
+ if (ret)
+ MCDRV_DBG_ERROR(mcd, "device pm unregister failed\n");
+#ifdef MC_BL_NOTIFIER
+ ret = unregister_bL_swicher_notifier(&switcher_nb);
+ if (ret)
+ MCDRV_DBG_ERROR(mcd, "device bl unregister failed\n");
+#endif
+ return ret;
+}
+
+#endif /* MC_PM_RUNTIME */
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+
+int mc_pm_clock_initialize(void)
+{
+ int ret = 0;
+
+ /* Get core clk */
+ mc_ce_core_clk = clk_get(mcd, "core_clk");
+ if (IS_ERR(mc_ce_core_clk)) {
+ ret = PTR_ERR(mc_ce_core_clk);
+ MCDRV_DBG_ERROR(mcd, "cannot get core clock\n");
+ goto error;
+ }
+ /* Get Interface clk */
+ mc_ce_iface_clk = clk_get(mcd, "iface_clk");
+ if (IS_ERR(mc_ce_iface_clk)) {
+ clk_put(mc_ce_core_clk);
+ ret = PTR_ERR(mc_ce_iface_clk);
+ MCDRV_DBG_ERROR(mcd, "cannot get iface clock\n");
+ goto error;
+ }
+ /* Get AXI clk */
+ mc_ce_bus_clk = clk_get(mcd, "bus_clk");
+ if (IS_ERR(mc_ce_bus_clk)) {
+ clk_put(mc_ce_iface_clk);
+ clk_put(mc_ce_core_clk);
+ ret = PTR_ERR(mc_ce_bus_clk);
+ MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock\n");
+ goto error;
+ }
+ return ret;
+
+error:
+ mc_ce_core_clk = NULL;
+ mc_ce_iface_clk = NULL;
+ mc_ce_bus_clk = NULL;
+
+ return ret;
+}
+
+void mc_pm_clock_finalize(void)
+{
+ if (mc_ce_iface_clk != NULL)
+ clk_put(mc_ce_iface_clk);
+
+ if (mc_ce_core_clk != NULL)
+ clk_put(mc_ce_core_clk);
+
+ if (mc_ce_bus_clk != NULL)
+ clk_put(mc_ce_bus_clk);
+}
+
+int mc_pm_clock_enable(void)
+{
+ int rc = 0;
+
+ rc = clk_prepare_enable(mc_ce_core_clk);
+ if (rc) {
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ } else {
+ rc = clk_prepare_enable(mc_ce_iface_clk);
+ if (rc) {
+ clk_disable_unprepare(mc_ce_core_clk);
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ } else {
+ rc = clk_prepare_enable(mc_ce_bus_clk);
+ if (rc) {
+ clk_disable_unprepare(mc_ce_iface_clk);
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ }
+ }
+ }
+ return rc;
+}
+
+void mc_pm_clock_disable(void)
+{
+ if (mc_ce_iface_clk != NULL)
+ clk_disable_unprepare(mc_ce_iface_clk);
+
+ if (mc_ce_core_clk != NULL)
+ clk_disable_unprepare(mc_ce_core_clk);
+
+ if (mc_ce_bus_clk != NULL)
+ clk_disable_unprepare(mc_ce_bus_clk);
+}
+
+#endif /* MC_CRYPTO_CLOCK_MANAGEMENT */
diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/mobicore_driver/pm.h
index 3e73b8b..332da34 100644
--- a/drivers/gud/mobicore_driver/pm.h
+++ b/drivers/gud/mobicore_driver/pm.h
@@ -31,5 +31,13 @@
int mc_pm_initialize(struct mc_context *context);
/* Free all Power Management resources*/
int mc_pm_free(void);
+/* Initialize secure crypto clocks */
+int mc_pm_clock_initialize(void);
+/* Free secure crypto clocks */
+void mc_pm_clock_finalize(void);
+/* Enable secure crypto clocks */
+int mc_pm_clock_enable(void);
+/* Disable secure crypto clocks */
+void mc_pm_clock_disable(void);
#endif /* _MC_PM_H_ */
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index f6ab3c2..de7b0e9 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -646,13 +646,15 @@
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_rsense;
- int32_t rc, sign_bit = 0;
+ int32_t rc = 0, sign_bit = 0;
if (!iadc || !iadc->iadc_initialized)
return -EPROBE_DEFER;
- if (iadc->external_rsense)
+ if (iadc->external_rsense) {
*rsense = iadc->rsense;
+ return rc;
+ }
rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
if (rc < 0) {
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index f74f2d5..d43bfbe 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -3,7 +3,7 @@
* FocalTech ft5x06 TouchScreen driver.
*
* Copyright (c) 2010 Focal tech Ltd.
- * 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
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/input/ft5x06_ts.h>
@@ -51,6 +52,7 @@
#define POINT_READ_BUF (3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
/*register address*/
+#define FT5X06_REG_ID 0xA3
#define FT5X06_REG_PMODE 0xA5
#define FT5X06_REG_FW_VER 0xA6
#define FT5X06_REG_POINT_RATE 0x88
@@ -67,6 +69,9 @@
#define FT5X06_I2C_VTG_MIN_UV 1800000
#define FT5X06_I2C_VTG_MAX_UV 1800000
+#define FT5X06_COORDS_ARR_SIZE 4
+#define MAX_BUTTONS 4
+
struct ts_event {
u16 x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */
u16 y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */
@@ -398,16 +403,139 @@
};
#endif
+#ifdef CONFIG_OF
+static int ft5x06_get_dt_coords(struct device *dev, char *name,
+ struct ft5x06_ts_platform_data *pdata)
+{
+ u32 coords[FT5X06_COORDS_ARR_SIZE];
+ struct property *prop;
+ struct device_node *np = dev->of_node;
+ int coords_size, rc;
+
+ prop = of_find_property(np, name, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ coords_size = prop->length / sizeof(u32);
+ if (coords_size != FT5X06_COORDS_ARR_SIZE) {
+ dev_err(dev, "invalid %s\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(np, name, coords, coords_size);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read %s\n", name);
+ return rc;
+ }
+
+ if (!strcmp(name, "focaltech,panel-coords")) {
+ pdata->panel_minx = coords[0];
+ pdata->panel_miny = coords[1];
+ pdata->panel_maxx = coords[2];
+ pdata->panel_maxy = coords[3];
+ } else if (!strcmp(name, "focaltech,display-coords")) {
+ pdata->x_min = coords[0];
+ pdata->y_min = coords[1];
+ pdata->x_max = coords[2];
+ pdata->y_max = coords[3];
+ } else {
+ dev_err(dev, "unsupported property %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ft5x06_parse_dt(struct device *dev,
+ struct ft5x06_ts_platform_data *pdata)
+{
+ int rc;
+ struct device_node *np = dev->of_node;
+ struct property *prop;
+ u32 temp_val, num_buttons;
+ u32 button_map[MAX_BUTTONS];
+
+ rc = ft5x06_get_dt_coords(dev, "focaltech,panel-coords", pdata);
+ if (rc && (rc != -EINVAL))
+ return rc;
+
+ rc = ft5x06_get_dt_coords(dev, "focaltech,display-coords", pdata);
+ if (rc)
+ return rc;
+
+ pdata->i2c_pull_up = of_property_read_bool(np,
+ "focaltech,i2c-pull-up");
+
+ pdata->no_force_update = of_property_read_bool(np,
+ "focaltech,no-force-update");
+ /* reset, irq gpio info */
+ pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio",
+ 0, &pdata->reset_gpio_flags);
+ if (pdata->reset_gpio < 0)
+ return pdata->reset_gpio;
+
+ pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio",
+ 0, &pdata->irq_gpio_flags);
+ if (pdata->irq_gpio < 0)
+ return pdata->irq_gpio;
+
+ rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
+ if (!rc)
+ pdata->family_id = temp_val;
+ else
+ return rc;
+
+ prop = of_find_property(np, "focaltech,button-map", NULL);
+ if (prop) {
+ num_buttons = prop->length / sizeof(temp_val);
+ if (num_buttons > MAX_BUTTONS)
+ return -EINVAL;
+
+ rc = of_property_read_u32_array(np,
+ "focaltech,button-map", button_map,
+ num_buttons);
+ if (rc) {
+ dev_err(dev, "Unable to read key codes\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+#else
+static int ft5x06_parse_dt(struct device *dev,
+ struct ft5x06_ts_platform_data *pdata)
+{
+ return -ENODEV;
+}
+#endif
+
static int ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const struct ft5x06_ts_platform_data *pdata = client->dev.platform_data;
+ struct ft5x06_ts_platform_data *pdata;
struct ft5x06_ts_data *data;
struct input_dev *input_dev;
u8 reg_value;
u8 reg_addr;
int err;
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct ft5x06_ts_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ err = ft5x06_parse_dt(&client->dev, pdata);
+ if (err)
+ return err;
+ } else
+ pdata = client->dev.platform_data;
+
if (!pdata) {
dev_err(&client->dev, "Invalid pdata\n");
return -EINVAL;
@@ -447,9 +575,9 @@
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
- input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
pdata->x_max, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
CFG_MAX_TOUCH_POINTS, 0, 0);
@@ -524,6 +652,19 @@
/* make sure CTP already finish startup process */
msleep(FT_STARTUP_DLY);
+ /* check the controller id */
+ reg_addr = FT5X06_REG_ID;
+ err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
+ if (err < 0) {
+ dev_err(&client->dev, "version read failed");
+ return err;
+ }
+
+ if (pdata->family_id != reg_value) {
+ dev_err(&client->dev, "%s:Unsupported controller\n", __func__);
+ goto free_reset_gpio;
+ }
+
/*get some register information */
reg_addr = FT5X06_REG_FW_VER;
err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
@@ -626,12 +767,22 @@
MODULE_DEVICE_TABLE(i2c, ft5x06_ts_id);
+#ifdef CONFIG_OF
+static struct of_device_id ft5x06_match_table[] = {
+ { .compatible = "focaltech,5x06",},
+ { },
+};
+#else
+#define ft5x06_match_table NULL
+#endif
+
static struct i2c_driver ft5x06_ts_driver = {
.probe = ft5x06_ts_probe,
.remove = __devexit_p(ft5x06_ts_remove),
.driver = {
.name = "ft5x06_ts",
.owner = THIS_MODULE,
+ .of_match_table = ft5x06_match_table,
#ifdef CONFIG_PM
.pm = &ft5x06_ts_pm_ops,
#endif
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ba94178..b9dd4ae 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -114,6 +114,12 @@
static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t synaptics_rmi4_mode_suspend_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_mode_resume_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data);
@@ -237,6 +243,12 @@
__ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
+ __ATTR(mode_suspend, S_IWUGO,
+ synaptics_rmi4_show_error,
+ synaptics_rmi4_mode_suspend_store),
+ __ATTR(mode_resume, S_IWUGO,
+ synaptics_rmi4_show_error,
+ synaptics_rmi4_mode_resume_store),
#endif
__ATTR(reset, S_IWUGO,
synaptics_rmi4_show_error,
@@ -288,6 +300,34 @@
return count;
}
+static ssize_t synaptics_rmi4_mode_suspend_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_mode_resume_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+
+ return count;
+}
+
#ifdef CONFIG_FB
static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
{
@@ -1031,8 +1071,6 @@
rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
"synaptics,i2c-pull-up");
- rmi4_pdata->regulator_en = of_property_read_bool(np,
- "synaptics,reg-en");
rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
@@ -1865,25 +1903,23 @@
if (on == false)
goto hw_shutdown;
- if (rmi4_data->board->regulator_en) {
- rmi4_data->vdd = regulator_get(&rmi4_data->i2c_client->dev,
- "vdd");
- if (IS_ERR(rmi4_data->vdd)) {
- dev_err(&rmi4_data->i2c_client->dev,
- "%s: Failed to get vdd regulator\n",
- __func__);
- return PTR_ERR(rmi4_data->vdd);
- }
+ rmi4_data->vdd = regulator_get(&rmi4_data->i2c_client->dev,
+ "vdd");
+ if (IS_ERR(rmi4_data->vdd)) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to get vdd regulator\n",
+ __func__);
+ return PTR_ERR(rmi4_data->vdd);
+ }
- if (regulator_count_voltages(rmi4_data->vdd) > 0) {
- retval = regulator_set_voltage(rmi4_data->vdd,
- RMI4_VTG_MIN_UV, RMI4_VTG_MAX_UV);
- if (retval) {
- dev_err(&rmi4_data->i2c_client->dev,
- "regulator set_vtg failed retval =%d\n",
- retval);
- goto err_set_vtg_vdd;
- }
+ if (regulator_count_voltages(rmi4_data->vdd) > 0) {
+ retval = regulator_set_voltage(rmi4_data->vdd,
+ RMI4_VTG_MIN_UV, RMI4_VTG_MAX_UV);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "regulator set_vtg failed retval =%d\n",
+ retval);
+ goto err_set_vtg_vdd;
}
}
@@ -1915,22 +1951,18 @@
if (rmi4_data->board->i2c_pull_up)
regulator_put(rmi4_data->vcc_i2c);
err_get_vtg_i2c:
- if (rmi4_data->board->regulator_en)
- if (regulator_count_voltages(rmi4_data->vdd) > 0)
- regulator_set_voltage(rmi4_data->vdd, 0,
- RMI4_VTG_MAX_UV);
+ if (regulator_count_voltages(rmi4_data->vdd) > 0)
+ regulator_set_voltage(rmi4_data->vdd, 0,
+ RMI4_VTG_MAX_UV);
err_set_vtg_vdd:
- if (rmi4_data->board->regulator_en)
- regulator_put(rmi4_data->vdd);
+ regulator_put(rmi4_data->vdd);
return retval;
hw_shutdown:
- if (rmi4_data->board->regulator_en) {
- if (regulator_count_voltages(rmi4_data->vdd) > 0)
- regulator_set_voltage(rmi4_data->vdd, 0,
- RMI4_VTG_MAX_UV);
- regulator_put(rmi4_data->vdd);
- }
+ if (regulator_count_voltages(rmi4_data->vdd) > 0)
+ regulator_set_voltage(rmi4_data->vdd, 0,
+ RMI4_VTG_MAX_UV);
+ regulator_put(rmi4_data->vdd);
if (rmi4_data->board->i2c_pull_up) {
if (regulator_count_voltages(rmi4_data->vcc_i2c) > 0)
regulator_set_voltage(rmi4_data->vcc_i2c, 0,
@@ -1947,23 +1979,21 @@
if (on == false)
goto power_off;
- if (rmi4_data->board->regulator_en) {
- retval = reg_set_optimum_mode_check(rmi4_data->vdd,
- RMI4_ACTIVE_LOAD_UA);
- if (retval < 0) {
- dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vdd set_opt failed rc=%d\n",
- retval);
- return retval;
- }
+ retval = reg_set_optimum_mode_check(rmi4_data->vdd,
+ RMI4_ACTIVE_LOAD_UA);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vdd set_opt failed rc=%d\n",
+ retval);
+ return retval;
+ }
- retval = regulator_enable(rmi4_data->vdd);
- if (retval) {
- dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vdd enable failed rc=%d\n",
- retval);
- goto error_reg_en_vdd;
- }
+ retval = regulator_enable(rmi4_data->vdd);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vdd enable failed rc=%d\n",
+ retval);
+ goto error_reg_en_vdd;
}
if (rmi4_data->board->i2c_pull_up) {
@@ -1990,18 +2020,14 @@
if (rmi4_data->board->i2c_pull_up)
reg_set_optimum_mode_check(rmi4_data->vdd, 0);
error_reg_opt_i2c:
- if (rmi4_data->board->regulator_en)
- regulator_disable(rmi4_data->vdd);
+ regulator_disable(rmi4_data->vdd);
error_reg_en_vdd:
- if (rmi4_data->board->regulator_en)
- reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+ reg_set_optimum_mode_check(rmi4_data->vdd, 0);
return retval;
power_off:
- if (rmi4_data->board->regulator_en) {
- reg_set_optimum_mode_check(rmi4_data->vdd, 0);
- regulator_disable(rmi4_data->vdd);
- }
+ reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+ regulator_disable(rmi4_data->vdd);
if (rmi4_data->board->i2c_pull_up) {
reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
regulator_disable(rmi4_data->vcc_i2c);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index aa69475..6324dff 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -14,12 +14,32 @@
if IOMMU_SUPPORT
# MSM IOMMU support
+
+# MSM_IOMMU always gets selected by whoever wants it.
config MSM_IOMMU
- bool "MSM IOMMU Support"
- depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226 || ARCH_APQ8084
+ bool
+
+# MSM IOMMUv0 support
+config MSM_IOMMU_V0
+ bool "MSM IOMMUv0 Support"
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8610
select IOMMU_API
+ select MSM_IOMMU
help
- Support for the IOMMUs found on certain Qualcomm SOCs.
+ Support for the IOMMUs (v0) found on certain Qualcomm SOCs.
+ These IOMMUs allow virtualization of the address space used by most
+ cores within the multimedia subsystem.
+
+ If unsure, say N here.
+
+# MSM IOMMUv1 support
+config MSM_IOMMU_V1
+ bool "MSM IOMMUv1 Support"
+ depends on ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8226 || ARCH_APQ8084
+ select IOMMU_API
+ select MSM_IOMMU
+ help
+ Support for the IOMMUs (v1) found on certain Qualcomm SOCs.
These IOMMUs allow virtualization of the address space used by most
cores within the multimedia subsystem.
@@ -28,7 +48,7 @@
# MSM IOMMU CPU-GPU sync programming support
config MSM_IOMMU_GPU_SYNC
bool "MSM IOMMU CPU-GPU Sync Support"
- depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU && MSM_REMOTE_SPINLOCK_SFPB
+ depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU_V0 && MSM_REMOTE_SPINLOCK_SFPB
help
Say Y here if you want to synchronize access to IOMMU configuration
port between CPU and GPU. CPU will grab a remote spinlock before
@@ -55,6 +75,20 @@
section mappings and TLB misses should be quite infrequent.
Most people can probably say Y here.
+config IOMMU_NON_SECURE
+ bool "Turns on programming of secure SMMU by kernel"
+ depends on MSM_IOMMU
+ help
+ Say Y here if you want the kernel to program all SMMUs regardless of
+ whether SMMUs are secure or not. A secure SMMU is an SMMU that has
+ its global address space programmed by the secure environment. In
+ addition some of the context banks might be owned/programmed by the
+ secure environment for a secure SMMU. Enabling this feature can be
+ used during testing when the secure environment is not available
+ and the kernel needs to program all the SMMUs.
+
+ If unsure, say N here.
+
# AMD IOMMU support
config AMD_IOMMU
bool "AMD IOMMU support"
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 096b53e..29a8b39 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -1,9 +1,14 @@
obj-$(CONFIG_IOMMU_API) += iommu.o
-obj-$(CONFIG_MSM_IOMMU) += msm_iommu-v0.o msm_iommu_dev-v0.o
-ifdef CONFIG_OF
-obj-$(CONFIG_MSM_IOMMU) += msm_iommu-v1.o msm_iommu_dev-v1.o msm_iommu_pagetable.o msm_iommu_sec.o
+obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o
+obj-$(CONFIG_MSM_IOMMU_V0) += msm_iommu-v0.o msm_iommu_dev-v0.o
+obj-$(CONFIG_MSM_IOMMU_V1) += msm_iommu-v1.o msm_iommu_dev-v1.o msm_iommu_pagetable.o msm_iommu_sec.o
+obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.o
+ifdef CONFIG_MSM_IOMMU_V0
+obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon-v0.o
endif
-obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.o msm_iommu_perfmon-v0.o msm_iommu_perfmon-v1.o
+ifdef CONFIG_MSM_IOMMU_V1
+obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon-v1.o
+endif
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 10fa5b1..49bfdb8 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -52,10 +52,6 @@
#define MSM_IOMMU_ATTR_CACHED_WB_NWA 0x2
#define MSM_IOMMU_ATTR_CACHED_WT 0x3
-struct bus_type msm_iommu_sec_bus_type = {
- .name = "msm_iommu_sec_bus",
-};
-
static int msm_iommu_unmap_range(struct iommu_domain *domain, unsigned int va,
unsigned int len);
@@ -224,7 +220,6 @@
.iommu_lock_acquire = _iommu_lock_acquire,
.iommu_lock_release = _iommu_lock_release,
};
-EXPORT_SYMBOL(iommu_access_ops_v0);
static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
{
@@ -1281,7 +1276,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",
@@ -1347,7 +1342,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 f90bf6c..653487b 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -42,15 +42,18 @@
static int __enable_regulators(struct msm_iommu_drvdata *drvdata)
{
- int ret = regulator_enable(drvdata->gdsc);
- if (ret)
- goto fail;
+ int ret = 0;
+ if (drvdata->gdsc) {
+ ret = regulator_enable(drvdata->gdsc);
+ if (ret)
+ goto fail;
- if (drvdata->alt_gdsc)
- ret = regulator_enable(drvdata->alt_gdsc);
+ if (drvdata->alt_gdsc)
+ ret = regulator_enable(drvdata->alt_gdsc);
- if (ret)
- regulator_disable(drvdata->gdsc);
+ if (ret)
+ regulator_disable(drvdata->gdsc);
+ }
fail:
return ret;
}
@@ -60,7 +63,8 @@
if (drvdata->alt_gdsc)
regulator_disable(drvdata->alt_gdsc);
- regulator_disable(drvdata->gdsc);
+ if (drvdata->gdsc)
+ regulator_disable(drvdata->gdsc);
}
static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
@@ -137,7 +141,6 @@
.iommu_lock_acquire = _iommu_lock_acquire,
.iommu_lock_release = _iommu_lock_release,
};
-EXPORT_SYMBOL(iommu_access_ops_v1);
void iommu_halt(const struct msm_iommu_drvdata *iommu_drvdata)
{
@@ -256,12 +259,46 @@
mb();
}
+#ifdef CONFIG_IOMMU_NON_SECURE
+static void __reset_iommu_secure(void __iomem *base)
+{
+ SET_NSACR(base, 0);
+ SET_NSCR2(base, 0);
+ SET_NSGFAR(base, 0);
+ SET_NSGFSRRESTORE(base, 0);
+ mb();
+}
+
+static void __program_iommu_secure(void __iomem *base)
+{
+ SET_NSCR0_SMCFCFG(base, 1);
+ SET_NSCR0_USFCFG(base, 1);
+ SET_NSCR0_STALLD(base, 1);
+ SET_NSCR0_GCFGFIE(base, 1);
+ SET_NSCR0_GCFGFRE(base, 1);
+ SET_NSCR0_GFIE(base, 1);
+ SET_NSCR0_GFRE(base, 1);
+ SET_NSCR0_CLIENTPD(base, 0);
+}
+
+#else
+static inline void __reset_iommu_secure(void __iomem *base)
+{
+}
+
+static inline void __program_iommu_secure(void __iomem *base)
+{
+}
+
+#endif
+
/*
* May only be called for non-secure iommus
*/
static void __program_iommu(void __iomem *base)
{
__reset_iommu(base);
+ __reset_iommu_secure(base);
SET_CR0_SMCFCFG(base, 1);
SET_CR0_USFCFG(base, 1);
@@ -272,6 +309,8 @@
SET_CR0_GFRE(base, 1);
SET_CR0_CLIENTPD(base, 0);
+ __program_iommu_secure(base);
+
mb(); /* Make sure writes complete before returning */
}
@@ -783,10 +822,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 " : "",
@@ -799,13 +840,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)
@@ -861,7 +920,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.c b/drivers/iommu/msm_iommu.c
new file mode 100644
index 0000000..ebecd11
--- /dev/null
+++ b/drivers/iommu/msm_iommu.c
@@ -0,0 +1,97 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/export.h>
+#include <linux/iommu.h>
+#include <mach/iommu.h>
+
+static DEFINE_MUTEX(iommu_list_lock);
+static LIST_HEAD(iommu_list);
+
+static struct iommu_access_ops *iommu_access_ops;
+
+struct bus_type msm_iommu_sec_bus_type = {
+ .name = "msm_iommu_sec_bus",
+};
+
+void msm_set_iommu_access_ops(struct iommu_access_ops *ops)
+{
+ iommu_access_ops = ops;
+}
+
+struct iommu_access_ops *msm_get_iommu_access_ops()
+{
+ BUG_ON(iommu_access_ops == NULL);
+ return iommu_access_ops;
+}
+EXPORT_SYMBOL(msm_get_iommu_access_ops);
+
+void msm_iommu_add_drv(struct msm_iommu_drvdata *drv)
+{
+ mutex_lock(&iommu_list_lock);
+ list_add(&drv->list, &iommu_list);
+ mutex_unlock(&iommu_list_lock);
+}
+
+void msm_iommu_remove_drv(struct msm_iommu_drvdata *drv)
+{
+ mutex_lock(&iommu_list_lock);
+ list_del(&drv->list);
+ mutex_unlock(&iommu_list_lock);
+}
+
+static int find_iommu_ctx(struct device *dev, void *data)
+{
+ struct msm_iommu_ctx_drvdata *c;
+
+ c = dev_get_drvdata(dev);
+ if (!c || !c->name)
+ return 0;
+
+ return !strcmp(data, c->name);
+}
+
+static struct device *find_context(struct device *dev, const char *name)
+{
+ return device_find_child(dev, (void *)name, find_iommu_ctx);
+}
+
+struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+ struct msm_iommu_drvdata *drv;
+ struct device *dev = NULL;
+
+ mutex_lock(&iommu_list_lock);
+ list_for_each_entry(drv, &iommu_list, list) {
+ dev = find_context(drv->dev, ctx_name);
+ if (dev)
+ break;
+ }
+ mutex_unlock(&iommu_list_lock);
+
+ 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);
+
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 4ee65d8..2d0fba2 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -32,64 +32,8 @@
#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);
- list_add(&drv->list, &iommu_list);
- mutex_unlock(&iommu_list_lock);
-}
-
-void msm_iommu_remove_drv(struct msm_iommu_drvdata *drv)
-{
- mutex_lock(&iommu_list_lock);
- list_del(&drv->list);
- mutex_unlock(&iommu_list_lock);
-}
-
-static int find_iommu_ctx(struct device *dev, void *data)
-{
- struct msm_iommu_ctx_drvdata *c;
-
- c = dev_get_drvdata(dev);
- if (!c || !c->name)
- return 0;
-
- return !strcmp(data, c->name);
-}
-
-static struct device *find_context(struct device *dev, const char *name)
-{
- return device_find_child(dev, (void *)name, find_iommu_ctx);
-}
-
-struct device *msm_iommu_get_ctx(const char *ctx_name)
-{
- struct msm_iommu_drvdata *drv;
- struct device *dev = NULL;
-
- mutex_lock(&iommu_list_lock);
- list_for_each_entry(drv, &iommu_list, list) {
- dev = find_context(drv->dev, ctx_name);
- if (dev)
- break;
- }
- mutex_unlock(&iommu_list_lock);
-
- 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);
+static struct iommu_access_ops *msm_iommu_access_ops;
static void msm_iommu_reset(void __iomem *base, void __iomem *glb_base, int ncb)
{
@@ -454,7 +398,7 @@
drvdata->dev = &pdev->dev;
- iommu_access_ops_v0.iommu_clk_on(drvdata);
+ msm_iommu_access_ops->iommu_clk_on(drvdata);
msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
@@ -462,7 +406,7 @@
if (ret)
goto fail_clk;
- iommu_access_ops_v0.iommu_clk_off(drvdata);
+ msm_iommu_access_ops->iommu_clk_off(drvdata);
pr_info("device %s mapped at %p, with %d ctx banks\n",
drvdata->name, drvdata->base, drvdata->ncb);
@@ -478,7 +422,7 @@
pr_info("%s: pmon not available.\n", drvdata->name);
} else {
pmon_info->iommu.base = drvdata->base;
- pmon_info->iommu.ops = &iommu_access_ops_v0;
+ pmon_info->iommu.ops = msm_iommu_access_ops;
pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v0();
pmon_info->iommu.iommu_name = drvdata->name;
pmon_info->iommu.always_on = 1;
@@ -497,7 +441,7 @@
return 0;
fail_clk:
- iommu_access_ops_v0.iommu_clk_off(drvdata);
+ msm_iommu_access_ops->iommu_clk_off(drvdata);
fail:
__put_bus_vote_client(drvdata);
fail_mem:
@@ -697,9 +641,9 @@
goto fail;
}
- iommu_access_ops_v0.iommu_clk_on(drvdata);
+ msm_iommu_access_ops->iommu_clk_on(drvdata);
__program_m2v_tables(drvdata, ctx_drvdata);
- iommu_access_ops_v0.iommu_clk_off(drvdata);
+ msm_iommu_access_ops->iommu_clk_off(drvdata);
dev_info(&pdev->dev, "context %s using bank %d\n", ctx_drvdata->name,
ctx_drvdata->num);
@@ -746,6 +690,11 @@
static int __init msm_iommu_driver_init(void)
{
int ret;
+
+ if (msm_soc_version_supports_iommu_v0()) {
+ msm_set_iommu_access_ops(&iommu_access_ops_v0);
+ msm_iommu_access_ops = msm_get_iommu_access_ops();
+ }
ret = platform_driver_register(&msm_iommu_driver);
if (ret != 0) {
pr_err("Failed to register IOMMU driver\n");
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index c0e05f4..119a126 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -115,8 +115,35 @@
static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
{
msm_bus_scale_unregister_client(drvdata->bus_client);
+ drvdata->bus_client = 0;
}
+#ifdef CONFIG_IOMMU_NON_SECURE
+static inline void get_secure_id(struct device_node *node,
+ struct msm_iommu_drvdata *drvdata)
+{
+}
+
+static inline void get_secure_ctx(struct device_node *node,
+ struct msm_iommu_ctx_drvdata *ctx_drvdata)
+{
+ ctx_drvdata->secure_context = 0;
+}
+#else
+static void get_secure_id(struct device_node *node,
+ struct msm_iommu_drvdata *drvdata)
+{
+ of_property_read_u32(node, "qcom,iommu-secure-id", &drvdata->sec_id);
+}
+
+static void get_secure_ctx(struct device_node *node,
+ struct msm_iommu_ctx_drvdata *ctx_drvdata)
+{
+ ctx_drvdata->secure_context =
+ of_property_read_bool(node, "qcom,secure-context");
+}
+#endif
+
static int msm_iommu_parse_dt(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
{
@@ -153,8 +180,7 @@
goto fail;
drvdata->sec_id = -1;
- of_property_read_u32(pdev->dev.of_node, "qcom,iommu-secure-id",
- &drvdata->sec_id);
+ get_secure_id(pdev->dev.of_node, drvdata);
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
if (r) {
@@ -263,13 +289,19 @@
drvdata->glb_base = drvdata->base;
- drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(drvdata->gdsc))
- return PTR_ERR(drvdata->gdsc);
+ if (of_get_property(pdev->dev.of_node, "vdd-supply", NULL)) {
- drvdata->alt_gdsc = devm_regulator_get(&pdev->dev, "qcom,alt-vdd");
- if (IS_ERR(drvdata->alt_gdsc))
- drvdata->alt_gdsc = NULL;
+ drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(drvdata->gdsc))
+ return PTR_ERR(drvdata->gdsc);
+
+ drvdata->alt_gdsc = devm_regulator_get(&pdev->dev,
+ "qcom,alt-vdd");
+ if (IS_ERR(drvdata->alt_gdsc))
+ drvdata->alt_gdsc = NULL;
+ } else {
+ pr_debug("Warning: No regulator specified for IOMMU\n");
+ }
drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(drvdata->pclk))
@@ -306,8 +338,6 @@
platform_set_drvdata(pdev, drvdata);
- msm_iommu_sec_set_access_ops(&iommu_access_ops_v1);
-
pmon_info = msm_iommu_pm_alloc(&pdev->dev);
if (pmon_info != NULL) {
ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
@@ -316,7 +346,7 @@
pr_info("%s: pmon not available.\n", drvdata->name);
} else {
pmon_info->iommu.base = drvdata->base;
- pmon_info->iommu.ops = &iommu_access_ops_v1;
+ pmon_info->iommu.ops = msm_get_iommu_access_ops();
pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v1();
pmon_info->iommu.iommu_name = drvdata->name;
ret = msm_iommu_pm_iommu_register(pmon_info);
@@ -356,10 +386,22 @@
int irq = 0, ret = 0;
u32 nsid;
- ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
- "qcom,secure-context");
+ get_secure_ctx(pdev->dev.of_node, ctx_drvdata);
- if (!ctx_drvdata->secure_context) {
+ if (ctx_drvdata->secure_context) {
+ irq = platform_get_irq(pdev, 1);
+ if (irq > 0) {
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ msm_iommu_secure_fault_handler_v2,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "msm_iommu_secure_irq", pdev);
+ if (ret) {
+ pr_err("Request IRQ %d failed with ret=%d\n",
+ irq, ret);
+ return ret;
+ }
+ }
+ } else {
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
@@ -482,6 +524,10 @@
{
int ret;
+ if (!msm_soc_version_supports_iommu_v0()) {
+ msm_set_iommu_access_ops(&iommu_access_ops_v1);
+ msm_iommu_sec_set_access_ops(&iommu_access_ops_v1);
+ }
ret = platform_driver_register(&msm_iommu_driver);
if (ret != 0) {
pr_err("Failed to register IOMMU driver\n");
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 74d8b48..a17a4e8 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -38,6 +38,7 @@
/* bitmap of the page sizes currently supported */
#define MSM_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
+/* commands for SCM_SVC_MP */
#define IOMMU_SECURE_CFG 2
#define IOMMU_SECURE_PTBL_SIZE 3
#define IOMMU_SECURE_PTBL_INIT 4
@@ -47,6 +48,9 @@
#define IOMMU_SECURE_UNMAP2 0x0C
#define IOMMU_TLBINVAL_FLAG 0x00000001
+/* commands for SCM_SVC_UTIL */
+#define IOMMU_DUMP_SMMU_FAULT_REGS 0X0C
+
static struct iommu_access_ops *iommu_access_ops;
struct msm_scm_paddr_list {
@@ -73,11 +77,154 @@
unsigned int flags;
};
+struct msm_scm_fault_regs_dump {
+ uint32_t dump_size;
+ uint32_t fsr_addr;
+ uint32_t fsr;
+ uint32_t far0_addr;
+ uint32_t far0;
+ uint32_t far1_addr;
+ uint32_t far1;
+ uint32_t par0_addr;
+ uint32_t par0;
+ uint32_t par1_addr;
+ uint32_t par1;
+ uint32_t fsyn0_addr;
+ uint32_t fsyn0;
+ uint32_t fsyn1_addr;
+ uint32_t fsyn1;
+ uint32_t ttbr0_addr;
+ uint32_t ttbr0;
+ uint32_t ttbr1_addr;
+ uint32_t ttbr1;
+ uint32_t ttbcr_addr;
+ uint32_t ttbcr;
+ uint32_t sctlr_addr;
+ uint32_t sctlr;
+ uint32_t actlr_addr;
+ uint32_t actlr;
+ uint32_t prrr_addr;
+ uint32_t prrr;
+ uint32_t nmrr_addr;
+ uint32_t nmrr;
+};
+
void msm_iommu_sec_set_access_ops(struct iommu_access_ops *access_ops)
{
iommu_access_ops = access_ops;
}
+static int msm_iommu_dump_fault_regs(int smmu_id, int cb_num,
+ struct msm_scm_fault_regs_dump *regs)
+{
+ int ret;
+
+ struct msm_scm_fault_regs_dump_req {
+ uint32_t id;
+ uint32_t cb_num;
+ phys_addr_t buff;
+ uint32_t len;
+ } req_info;
+ int resp;
+
+ req_info.id = smmu_id;
+ req_info.cb_num = cb_num;
+ req_info.buff = virt_to_phys(regs);
+ req_info.len = sizeof(*regs);
+
+ ret = scm_call(SCM_SVC_UTIL, IOMMU_DUMP_SMMU_FAULT_REGS,
+ &req_info, sizeof(req_info), &resp, 1);
+
+ return ret;
+}
+
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct msm_iommu_drvdata *drvdata;
+ struct msm_iommu_ctx_drvdata *ctx_drvdata;
+ struct msm_scm_fault_regs_dump *regs;
+ int tmp, ret = IRQ_HANDLED;
+
+ iommu_access_ops->iommu_lock_acquire();
+
+ BUG_ON(!pdev);
+
+ drvdata = dev_get_drvdata(pdev->dev.parent);
+ BUG_ON(!drvdata);
+
+ ctx_drvdata = dev_get_drvdata(&pdev->dev);
+ BUG_ON(!ctx_drvdata);
+
+ regs = kmalloc(sizeof(*regs), GFP_KERNEL);
+ if (!regs) {
+ pr_err("%s: Couldn't allocate memory\n", __func__);
+ goto lock_release;
+ }
+
+ if (!drvdata->ctx_attach_count) {
+ pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("Power is OFF. Unable to read page fault information\n");
+ /*
+ * We cannot determine which context bank caused the issue so
+ * we just return handled here to ensure IRQ handler code is
+ * happy
+ */
+ goto free_regs;
+ }
+
+ iommu_access_ops->iommu_clk_on(drvdata);
+ tmp = msm_iommu_dump_fault_regs(drvdata->sec_id,
+ ctx_drvdata->num, regs);
+ iommu_access_ops->iommu_clk_off(drvdata);
+
+ if (tmp) {
+ pr_err("%s: Couldn't dump fault registers!\n", __func__);
+ goto free_regs;
+ } else if (regs->fsr) {
+ struct msm_iommu_context_regs ctx_regs = {
+ .far = regs->far0,
+ .par = regs->par0,
+ .fsr = regs->fsr,
+ .fsynr0 = regs->fsyn0,
+ .fsynr1 = regs->fsyn1,
+ .ttbr0 = regs->ttbr0,
+ .ttbr1 = regs->ttbr1,
+ .sctlr = regs->sctlr,
+ .actlr = regs->actlr,
+ .prrr = regs->prrr,
+ .nmrr = regs->nmrr,
+ };
+
+ if (!ctx_drvdata->attached_domain) {
+ pr_err("Bad domain in interrupt handler\n");
+ tmp = -ENOSYS;
+ } else {
+ tmp = report_iommu_fault(ctx_drvdata->attached_domain,
+ &ctx_drvdata->pdev->dev,
+ regs->far0, 0);
+ }
+
+ /* if the fault wasn't handled by someone else: */
+ if (tmp == -ENOSYS) {
+ pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("context = %s (%d)\n", ctx_drvdata->name,
+ ctx_drvdata->num);
+ pr_err("Interesting registers:\n");
+ print_ctx_regs(&ctx_regs);
+ }
+ } else {
+ ret = IRQ_NONE;
+ }
+free_regs:
+ kfree(regs);
+lock_release:
+ iommu_access_ops->iommu_lock_release();
+ return ret;
+}
+
static int msm_iommu_sec_ptbl_init(void)
{
struct device_node *np;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 9101a3d..4835d62 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -23,6 +23,7 @@
#include <linux/spmi.h>
#include <linux/qpnp/pwm.h>
#include <linux/workqueue.h>
+#include <linux/regulator/consumer.h>
#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
@@ -307,6 +308,7 @@
struct pwm_duty_cycles *duty_cycles;
u8 mode;
u8 enable;
+ bool use_blink;
};
/**
@@ -362,6 +364,9 @@
* @second_addr - address of secondary flash to be written
* @safety_timer - enable safety timer or watchdog timer
* @torch_enable - enable flash LED torch mode
+ * @regulator_get - regulator attached or not
+ * @flash_on - flash status, on or off
+ * @flash_boost_reg - boost regulator for flash
*/
struct flash_config_data {
u8 current_prgm;
@@ -376,6 +381,9 @@
u16 second_addr;
bool safety_timer;
bool torch_enable;
+ bool regulator_get;
+ bool flash_on;
+ struct regulator *flash_boost_reg;
};
/**
@@ -935,8 +943,9 @@
static void qpnp_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- int rc;
+ int rc, i;
struct qpnp_led_data *led;
+ struct qpnp_led_data *led_array;
led = container_of(led_cdev, struct qpnp_led_data, cdev);
if (value < LED_OFF || value > led->cdev.max_brightness) {
@@ -944,6 +953,33 @@
return;
}
+ if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1) {
+ if (!led->flash_cfg->flash_on && value > 0) {
+ led_array = dev_get_drvdata(&led->spmi_dev->dev);
+ if (!led_array) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to unable to get array\n");
+ return;
+ }
+
+ for (i = 0; i < led->num_leds; i++) {
+ if (led_array[i].flash_cfg->regulator_get) {
+ rc = regulator_enable(led_array[i].\
+ flash_cfg->\
+ flash_boost_reg);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Regulator enable" \
+ "failed(%d)\n",
+ rc);
+ return;
+ }
+ }
+ }
+ led->flash_cfg->flash_on = true;
+ }
+ }
+
spin_lock(&led->lock);
led->cdev.brightness = value;
@@ -986,6 +1022,32 @@
break;
}
spin_unlock(&led->lock);
+
+ if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1) {
+ if (led->flash_cfg->flash_on && !value) {
+ led_array = dev_get_drvdata(&led->spmi_dev->dev);
+ if (!led_array) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to get LED array\n");
+ return;
+ }
+
+ for (i = 0; i < led->num_leds; i++) {
+ if (led_array[i].flash_cfg->regulator_get) {
+ rc = regulator_disable(led_array[i]\
+ .flash_cfg->flash_boost_reg);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to disable" \
+ " regulator(%d)\n",
+ rc);
+ return;
+ }
+ }
+ }
+ led->flash_cfg->flash_on = false;
+ }
+ }
}
static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
@@ -1222,8 +1284,122 @@
return count;
}
+static int 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 void led_blink(struct qpnp_led_data *led,
+ struct pwm_config_data *pwm_cfg)
+{
+ u8 previous_mode;
+
+ previous_mode = pwm_cfg->mode;
+ if (pwm_cfg->use_blink) {
+ if (led->cdev.brightness) {
+ if (led->id == QPNP_ID_LED_MPP)
+ led->mpp_cfg->pwm_mode = LPG_MODE;
+ pwm_cfg->mode = LPG_MODE;
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ if (led->id == QPNP_ID_LED_MPP)
+ led->mpp_cfg->pwm_mode = previous_mode;
+ pwm_cfg->mode = previous_mode;
+ } else {
+ pwm_free(pwm_cfg->pwm_dev);
+ qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ }
+ }
+}
+
+static ssize_t blink_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_led_data *led;
+ unsigned long blinking;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL;
+
+ ret = kstrtoul(buf, 10, &blinking);
+ if (ret)
+ return ret;
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+ led->cdev.brightness = blinking ? led->cdev.max_brightness : 0;
+
+ switch (led->id) {
+ case QPNP_ID_LED_MPP:
+ led_blink(led, led->mpp_cfg->pwm_cfg);
+ break;
+ case QPNP_ID_RGB_RED:
+ case QPNP_ID_RGB_GREEN:
+ case QPNP_ID_RGB_BLUE:
+ led_blink(led, led->rgb_cfg->pwm_cfg);
+ break;
+ default:
+ dev_err(&led->spmi_dev->dev, "Invalid LED id type for blink\n");
+ return -EINVAL;
+ }
+ return count;
+}
+
static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
+static DEVICE_ATTR(blink, 0664, NULL, blink_store);
static struct attribute *led_attrs[] = {
&dev_attr_led_mode.attr,
@@ -1235,10 +1411,21 @@
.attrs = led_attrs,
};
+static struct attribute *blink_attrs[] = {
+ &dev_attr_blink.attr,
+ NULL
+};
+
+static const struct attribute_group blink_attr_group = {
+ .attrs = blink_attrs,
+};
+
static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
{
int rc;
+ led->flash_cfg->flash_on = false;
+
rc = qpnp_led_masked_write(led,
FLASH_LED_STROBE_CTRL(led->base),
FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
@@ -1324,63 +1511,6 @@
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;
@@ -1655,7 +1785,7 @@
}
static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
- struct device_node *node)
+ struct device_node *node, bool *reg_set)
{
int rc;
u32 val;
@@ -1672,11 +1802,39 @@
led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
+ if (!*reg_set) {
+ led->flash_cfg->flash_boost_reg =
+ regulator_get(&led->spmi_dev->dev,
+ "flash_boost");
+ if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
+ rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
+ dev_err(&led->spmi_dev->dev,
+ "Regulator get failed(%d)\n", rc);
+ return rc;
+ }
+ led->flash_cfg->regulator_get = true;
+ *reg_set = true;
+ } else
+ led->flash_cfg->regulator_get = false;
} else if (led->id == QPNP_ID_FLASH1_LED1) {
led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
+ if (!*reg_set) {
+ led->flash_cfg->flash_boost_reg =
+ regulator_get(&led->spmi_dev->dev,
+ "flash_boost");
+ if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
+ rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
+ dev_err(&led->spmi_dev->dev,
+ "Regulator get failed(%d)\n", rc);
+ return rc;
+ }
+ led->flash_cfg->regulator_get = true;
+ *reg_set = true;
+ } else
+ led->flash_cfg->regulator_get = false;
} else {
dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
return -EINVAL;
@@ -1754,14 +1912,18 @@
return rc;
}
- if (pwm_cfg->mode == LPG_MODE) {
+ pwm_cfg->use_blink =
+ of_property_read_bool(node, "qcom,use-blink");
+
+ if (pwm_cfg->mode == LPG_MODE || pwm_cfg->use_blink) {
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;
+ rc = -ENOMEM;
+ goto bad_lpg_params;
}
prop = of_find_property(node, "qcom,duty-pcts",
@@ -1769,11 +1931,13 @@
if (!prop) {
dev_err(&spmi_dev->dev, "Looking up property " \
"node qcom,duty-pcts failed\n");
- return -ENODEV;
+ rc = -ENODEV;
+ goto bad_lpg_params;
} else if (!pwm_cfg->duty_cycles->num_duty_pcts) {
dev_err(&spmi_dev->dev, "Invalid length of " \
"duty pcts\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto bad_lpg_params;
}
pwm_cfg->duty_cycles->duty_pcts =
@@ -1783,7 +1947,8 @@
if (!pwm_cfg->duty_cycles->duty_pcts) {
dev_err(&spmi_dev->dev,
"Unable to allocate memory\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto bad_lpg_params;
}
temp_cfg = devm_kzalloc(&spmi_dev->dev,
@@ -1792,7 +1957,8 @@
if (!temp_cfg) {
dev_err(&spmi_dev->dev, "Failed to allocate " \
"memory for duty pcts\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto bad_lpg_params;
}
memcpy(temp_cfg, prop->value,
@@ -1807,21 +1973,21 @@
pwm_cfg->lut_params.start_idx = val;
pwm_cfg->duty_cycles->start_idx = val;
} else
- return rc;
+ goto bad_lpg_params;
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;
+ goto bad_lpg_params;
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;
+ goto bad_lpg_params;
pwm_cfg->lut_params.ramp_step_ms =
QPNP_LUT_RAMP_STEP_DEFAULT;
@@ -1829,19 +1995,28 @@
if (!rc)
pwm_cfg->lut_params.ramp_step_ms = val;
else if (rc != -EINVAL)
- return rc;
+ goto bad_lpg_params;
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;
+ goto bad_lpg_params;
pwm_cfg->lut_params.idx_len =
pwm_cfg->duty_cycles->num_duty_pcts;
}
return 0;
+
+bad_lpg_params:
+ pwm_cfg->use_blink = false;
+ if (pwm_cfg->mode == PWM_MODE) {
+ dev_err(&spmi_dev->dev, "LPG parameters not set for" \
+ " blink mode, defaulting to PWM mode\n");
+ return 0;
+ }
+ return rc;
};
static int qpnp_led_get_mode(const char *mode)
@@ -2038,6 +2213,7 @@
struct device_node *node, *temp;
int rc, i, num_leds = 0, parsed_leds = 0;
const char *led_label;
+ bool regulator_probe = false;
node = spmi->dev.of_node;
if (node == NULL)
@@ -2120,7 +2296,9 @@
}
} else if (strncmp(led_label, "flash", sizeof("flash"))
== 0) {
- rc = qpnp_get_config_flash(led, temp);
+ if (!of_find_property(node, "flash_boost-supply", NULL))
+ regulator_probe = true;
+ rc = qpnp_get_config_flash(led, temp, ®ulator_probe);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
"Unable to read flash config data\n");
@@ -2179,16 +2357,35 @@
}
+ if (led->id == QPNP_ID_LED_MPP) {
+ if (!led->mpp_cfg->pwm_cfg)
+ break;
+ if (led->mpp_cfg->pwm_cfg->use_blink) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &blink_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
+ } else if ((led->id == QPNP_ID_RGB_RED) ||
+ (led->id == QPNP_ID_RGB_GREEN) ||
+ (led->id == QPNP_ID_RGB_BLUE)) {
+ if (led->rgb_cfg->pwm_cfg->use_blink) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &blink_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
+ }
+
/* configure default state */
if (led->default_on) {
led->cdev.brightness = led->cdev.max_brightness;
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
if (led->turn_off_delay_ms > 0)
qpnp_led_turn_off(led);
} else
led->cdev.brightness = LED_OFF;
- qpnp_led_set(&led->cdev, led->cdev.brightness);
-
parsed_leds++;
}
dev_set_drvdata(&spmi->dev, led_array);
@@ -2212,6 +2409,9 @@
break;
case QPNP_ID_FLASH1_LED0:
case QPNP_ID_FLASH1_LED1:
+ if (led_array[i].flash_cfg->regulator_get)
+ regulator_put(led_array[i].flash_cfg-> \
+ flash_boost_reg);
sysfs_remove_group(&led_array[i].cdev.dev->kobj,
&led_attr_group);
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index b8c3c44..bd4344b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -442,6 +442,45 @@
}
EXPORT_SYMBOL(dvb_dmx_video_pattern_search);
+/**
+ * dvb_dmx_notify_section_event() - Notify demux event for all filters of a
+ * specified section feed.
+ *
+ * @feed: dvb_demux_feed object
+ * @event: demux event to notify
+ * @should_lock: specifies whether the function should lock the demux
+ *
+ * Caller is responsible for locking the demux properly, either by doing the
+ * locking itself and setting 'should_lock' to 0, or have the function do it
+ * by setting 'should_lock' to 1.
+ */
+int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
+ struct dmx_data_ready *event, int should_lock)
+{
+ struct dvb_demux_filter *f;
+
+ if (feed == NULL || event == NULL || feed->type != DMX_TYPE_SEC)
+ return -EINVAL;
+
+ if (!should_lock && !spin_is_locked(&feed->demux->lock))
+ return -EINVAL;
+
+ if (should_lock)
+ spin_lock(&feed->demux->lock);
+
+ f = feed->filter;
+ while (f && feed->feed.sec.is_filtering) {
+ feed->data_ready_cb.sec(&f->filter, event);
+ f = f->next;
+ }
+
+ if (should_lock)
+ spin_unlock(&feed->demux->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(dvb_dmx_notify_section_event);
+
static int dvb_dmx_check_pes_end(struct dvb_demux_feed *feed)
{
struct dmx_data_ready data;
@@ -1310,8 +1349,7 @@
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);
+ dvb_dmx_notify_section_event(feed, &dmx_data_ready, 0);
else
feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
}
@@ -2735,7 +2773,7 @@
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
struct dvb_demux *dvbdmx = feed->demux;
struct dmx_data_ready data;
- int ret;
+ int ret = 0;
data.data_length = 0;
@@ -2760,13 +2798,11 @@
switch (cmd->type) {
case DMX_OOB_CMD_EOS:
data.status = DMX_OK_EOS;
- ret = feed->data_ready_cb.sec(&feed->filter->filter, &data);
break;
case DMX_OOB_CMD_MARKER:
data.status = DMX_OK_MARKER;
data.marker.id = cmd->params.marker.id;
- ret = feed->data_ready_cb.sec(&feed->filter->filter, &data);
break;
default:
@@ -2774,6 +2810,9 @@
break;
}
+ if (!ret)
+ ret = dvb_dmx_notify_section_event(feed, &data, 1);
+
mutex_unlock(&dvbdmx->mutex);
return ret;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 9fb1a12..aeafa57 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -325,6 +325,8 @@
u64 curr_match_tsp, u64 prev_match_tsp,
u64 curr_pusi_tsp, u64 prev_pusi_tsp);
void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed);
+int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
+ struct dmx_data_ready *event, int should_lock);
/**
* dvb_dmx_is_video_feed - Returns whether the PES feed
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 52864ae..525a545 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -36,6 +36,16 @@
This config macro is required targets based on 8960,
8930 and 8064 platforms.
+config MSM_CSI22_HEADER
+ bool "Qualcomm MSM CSI 2.2 Header"
+ depends on MSMB_CAMERA
+ ---help---
+ Enable support for CSI drivers to include 2.2
+ header. This header has register macros and its
+ values and bit mask for register configuration bits
+ This config macro is required targets based on 8610
+ platform.
+
config MSM_CSI30_HEADER
bool "Qualcomm MSM CSI 3.0 Header"
depends on MSMB_CAMERA
@@ -82,6 +92,15 @@
of any CID of CSID can be routed to of of pixel or raw
data interface in VFE.
+config MSM_ISPIF_V1
+ bool "Qualcomm MSM Image Signal Processing interface support"
+ depends on MSMB_CAMERA
+ ---help---
+ Enable support for Image Signal Processing interface module.
+ This module acts as a crossbar between CSID and VFE. Output
+ of any CID of MSM_CSI22_HEADER can be routed to of pixel
+ or raw data interface in VFE.
+
config S5K3L1YX
bool "Sensor S5K3L1YX (BAYER 12M)"
depends on MSMB_CAMERA
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 88f2f08..2a2656f 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
@@ -420,7 +420,7 @@
static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t buf_index,
- struct timeval *tv, uint32_t frame_id)
+ struct timeval *tv, uint32_t frame_id, uint32_t output_format)
{
int rc = -1;
unsigned long flags;
@@ -467,6 +467,7 @@
} else {
buf_info->vb2_buf->v4l2_buf.timestamp = *tv;
buf_info->vb2_buf->v4l2_buf.sequence = frame_id;
+ buf_info->vb2_buf->v4l2_buf.reserved = output_format;
buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf,
bufq->session_id, bufq->stream_id);
}
@@ -567,11 +568,18 @@
if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) {
buf_info = msm_isp_get_buf_ptr(buf_mgr,
info->handle, info->buf_idx);
- if (info->dirty_buf)
- msm_isp_put_buf(buf_mgr, info->handle, info->buf_idx);
- else
- msm_isp_buf_done(buf_mgr, info->handle, info->buf_idx,
- buf_info->tv, buf_info->frame_id);
+ if (info->dirty_buf) {
+ rc = msm_isp_put_buf(buf_mgr,
+ info->handle, info->buf_idx);
+ } else {
+ if (BUF_SRC(bufq->stream_id))
+ pr_err("%s: Invalid native buffer state\n",
+ __func__);
+ else
+ rc = msm_isp_buf_done(buf_mgr,
+ info->handle, info->buf_idx,
+ buf_info->tv, buf_info->frame_id, 0);
+ }
} else {
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
if (BUF_SRC(bufq->stream_id)) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index fda1a57..6d6ff9d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -108,7 +108,7 @@
int (*buf_done) (struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t buf_index,
- struct timeval *tv, uint32_t frame_id);
+ struct timeval *tv, uint32_t frame_id, uint32_t output_format);
int (*buf_divert) (struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t buf_index,
struct timeval *tv, uint32_t frame_id);
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 ff9c9b8..2c5e136 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -38,6 +38,10 @@
.compatible = "qcom,vfe40",
.data = &vfe40_hw_info,
},
+ {
+ .compatible = "qcom,vfe32",
+ .data = &vfe32_hw_info,
+ },
{}
};
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 6de6e74..f1f4c17 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -207,12 +207,21 @@
AVALIABLE,
INACTIVE,
ACTIVE,
- PAUSE,
+ PAUSED,
START_PENDING,
STOP_PENDING,
+ PAUSE_PENDING,
+ RESUME_PENDING,
STARTING,
STOPPING,
- PAUSE_PENDING,
+ PAUSING,
+ RESUMING,
+};
+
+enum msm_vfe_axi_cfg_update_state {
+ NO_AXI_CFG_UPDATE,
+ APPLYING_UPDATE_RESUME,
+ UPDATE_REQUESTED,
};
#define VFE_NO_DROP 0xFFFFFFFF
@@ -251,6 +260,7 @@
uint32_t init_frame_drop;
uint32_t burst_frame_count;/*number of sof before burst stop*/
uint8_t framedrop_update;
+ spinlock_t lock;
/*Bandwidth calculation info*/
uint32_t max_width;
@@ -263,6 +273,7 @@
uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/
uint32_t runtime_num_burst_capture;
uint8_t runtime_framedrop_update;
+ uint32_t runtime_output_format;
};
struct msm_vfe_axi_composite_info {
@@ -298,6 +309,7 @@
composite_info[MAX_NUM_COMPOSITE_MASK];
uint8_t num_used_composite_mask;
uint32_t stream_update;
+ atomic_t axi_cfg_update;
enum msm_isp_camif_update_state pipeline_update;
struct msm_vfe_src_info src_info[VFE_SRC_MAX];
uint16_t stream_handle_cnt;
@@ -407,6 +419,7 @@
struct msm_vfe_error_info error_info;
struct msm_isp_buf_mgr *buf_mgr;
int dump_reg;
+ int vfe_clk_idx;
uint32_t vfe_open_cnt;
};
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 3a94af3..4c5f258 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -22,7 +22,7 @@
#include "msm.h"
#include "msm_camera_io_util.h"
-#define VFE32_BURST_LEN 3
+#define VFE32_BURST_LEN 1
#define VFE32_UB_SIZE 1024
#define VFE32_EQUAL_SLICE_UB 204
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
@@ -40,7 +40,17 @@
(~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1))
#define VFE32_CLK_IDX 0
-static struct msm_cam_clk_info msm_vfe32_clk_info[] = {
+static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = {
+ /*vfe32 clock info for B-family: 8610 */
+ {"vfe_clk_src", 266670000},
+ {"vfe_clk", -1},
+ {"vfe_ahb_clk", -1},
+ {"csi_vfe_clk", -1},
+ {"bus_clk", -1},
+};
+
+static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = {
+ /*vfe32 clock info for A-family: 8960 */
{"vfe_clk", 266667000},
{"vfe_pclk", -1},
{"csi_vfe_clk", -1},
@@ -49,6 +59,7 @@
static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev)
{
int rc = -1;
+ vfe_dev->vfe_clk_idx = 0;
rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
if (rc < 0) {
pr_err("%s: Bandwidth registration Failed!\n", __func__);
@@ -63,10 +74,18 @@
}
}
- rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
- vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 1);
- if (rc < 0)
- goto clk_enable_failed;
+ rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
+ vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
+ if (rc < 0) {
+ rc = msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_2_clk_info), 1);
+ if (rc < 0)
+ goto clk_enable_failed;
+ else
+ vfe_dev->vfe_clk_idx = 2;
+ } else
+ vfe_dev->vfe_clk_idx = 1;
vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start,
resource_size(vfe_dev->vfe_mem));
@@ -87,8 +106,14 @@
irq_req_failed:
iounmap(vfe_dev->vfe_base);
vfe_remap_failed:
- msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
- vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 1)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 2)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
clk_enable_failed:
regulator_disable(vfe_dev->fs_vfe);
fs_failed:
@@ -102,8 +127,14 @@
free_irq(vfe_dev->vfe_irq->start, vfe_dev);
tasklet_kill(&vfe_dev->vfe_tasklet);
iounmap(vfe_dev->vfe_base);
- msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
- vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 1)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 2)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
regulator_disable(vfe_dev->fs_vfe);
msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
}
@@ -330,7 +361,18 @@
static void msm_vfe32_axi_reload_wm(
struct vfe_device *vfe_dev, uint32_t reload_mask)
{
- msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
+ if (!vfe_dev->pdev->dev.of_node) {
+ /*vfe32 A-family: 8960*/
+ msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
+ } else {
+ /*vfe32 B-family: 8610*/
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x24);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x20);
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18);
+ msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600);
+ msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38);
+ }
}
static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
@@ -638,6 +680,7 @@
} else {
switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV14:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
break;
@@ -913,14 +956,22 @@
goto vfe_no_resource;
}
- vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+ if (!vfe_dev->pdev->dev.of_node)
+ vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+ else
+ vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0");
+
if (!vfe_dev->iommu_ctx[0]) {
pr_err("%s: no iommux ctx resource?\n", __func__);
rc = -ENODEV;
goto vfe_no_resource;
}
- vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+ if (!vfe_dev->pdev->dev.of_node)
+ vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+ else
+ vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe0");
+
if (!vfe_dev->iommu_ctx[1]) {
pr_err("%s: no iommux ctx resource?\n", __func__);
rc = -ENODEV;
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 c4a1b63..1c146d0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -29,8 +29,9 @@
#define CDBG(fmt, args...) do { } while (0)
#endif
-#define VFE40_V1_VERSION 0x10000018
-#define VFE40_V2_VERSION 0x1001001A
+#define VFE40_8974V1_VERSION 0x10000018
+#define VFE40_8974V2_VERSION 0x1001001A
+#define VFE40_8x26_VERSION 0x20000013
#define VFE40_BURST_LEN 3
#define VFE40_STATS_BURST_LEN 2
@@ -90,7 +91,8 @@
static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev)
{
void __iomem *vfebase = vfe_dev->vfe_base;
- if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+ if (vfe_dev->vfe_hw_version == VFE40_8974V1_VERSION ||
+ vfe_dev->vfe_hw_version == VFE40_8x26_VERSION) {
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
@@ -99,7 +101,7 @@
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
- } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+ } else if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION) {
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
@@ -108,81 +110,138 @@
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ } else {
+ BUG();
+ pr_err("%s: QOS is NOT configured for HW Version %x\n",
+ __func__, vfe_dev->vfe_hw_version);
}
}
+static void msm_vfe40_init_vbif_parms_8974_v1(struct vfe_device *vfe_dev)
+{
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10010110,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000030,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000001,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ return;
+}
+
+static void msm_vfe40_init_vbif_parms_8974_v2(struct vfe_device *vfe_dev)
+{
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000003,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ return;
+}
+
+static void msm_vfe40_init_vbif_parms_8x26(struct vfe_device *vfe_dev)
+{
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x000000FF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x00FF00FF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000003,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ return;
+}
+
static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev)
{
- void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
- if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
- msm_camera_io_w(0x1,
- vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w(0x10010110,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
- msm_camera_io_w(0x00000030,
- vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w(0x00000FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w(0x0FFF0FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
- msm_camera_io_w(0x00000001,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w(0x22222222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
- msm_camera_io_w(0x00002222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
- } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
- msm_camera_io_w(0x1,
- vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w(0x00000010,
- vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w(0x00000010,
- vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w(0x00000010,
- vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w(0x00000FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w(0x0FFF0FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
- msm_camera_io_w(0x00000003,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w(0x22222222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
- msm_camera_io_w(0x00002222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ switch (vfe_dev->vfe_hw_version) {
+ case VFE40_8974V1_VERSION:
+ msm_vfe40_init_vbif_parms_8974_v1(vfe_dev);
+ break;
+ case VFE40_8974V2_VERSION:
+ msm_vfe40_init_vbif_parms_8974_v2(vfe_dev);
+ break;
+ case VFE40_8x26_VERSION:
+ msm_vfe40_init_vbif_parms_8x26(vfe_dev);
+ break;
+ default:
+ BUG();
+ pr_err("%s: VBIF is NOT configured for HW Version %x\n",
+ __func__, vfe_dev->vfe_hw_version);
+ break;
}
+
}
static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev)
@@ -472,6 +531,8 @@
msm_isp_axi_stream_update(vfe_dev);
if (atomic_read(&vfe_dev->stats_data.stats_update))
msm_isp_stats_stream_update(vfe_dev);
+ if (atomic_read(&vfe_dev->axi_data.axi_cfg_update))
+ msm_isp_axi_cfg_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
msm_isp_update_error_frame_count(vfe_dev);
@@ -760,6 +821,7 @@
uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base);
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
@@ -836,6 +898,7 @@
} else {
switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV14:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
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 e3d036f6..f470d36 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
@@ -43,6 +43,7 @@
memset(&axi_data->stream_info[i], 0,
sizeof(struct msm_vfe_axi_stream));
+ spin_lock_init(&axi_data->stream_info[i].lock);
axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id;
axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id;
axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert;
@@ -101,6 +102,8 @@
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
stream_info->num_planes = 2;
@@ -142,6 +145,7 @@
}
stream_info->output_format = stream_cfg_cmd->output_format;
+ stream_info->runtime_output_format = stream_info->output_format;
stream_info->stream_src = stream_cfg_cmd->stream_src;
stream_info->frame_based = stream_cfg_cmd->frame_base;
return 0;
@@ -197,6 +201,15 @@
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width / 2;
break;
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
+ if (plane_cfg[plane_idx].output_plane_format == Y_PLANE)
+ size = plane_cfg[plane_idx].output_height *
+ plane_cfg[plane_idx].output_width;
+ else
+ size = plane_cfg[plane_idx].output_height *
+ plane_cfg[plane_idx].output_width / 8;
+ break;
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
size = plane_cfg[plane_idx].output_height *
@@ -278,19 +291,32 @@
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
{
int rc = 0, i;
+ unsigned long flags;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
struct msm_vfe_axi_stream *stream_info;
enum msm_vfe_axi_state valid_state =
(stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE;
-
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])];
+ spin_lock_irqsave(&stream_info->lock, flags);
if (stream_info->state != valid_state) {
- pr_err("%s: Invalid stream state\n", __func__);
- rc = -EINVAL;
- break;
+ if ((stream_info->state == PAUSING ||
+ stream_info->state == PAUSED ||
+ stream_info->state == RESUME_PENDING ||
+ stream_info->state == RESUMING) &&
+ stream_cfg_cmd->cmd == STOP_STREAM) {
+ stream_info->state = ACTIVE;
+ } else {
+ pr_err("%s: Invalid stream state: %d\n",
+ __func__, stream_info->state);
+ spin_unlock_irqrestore(
+ &stream_info->lock, flags);
+ rc = -EINVAL;
+ break;
+ }
}
+ spin_unlock_irqrestore(&stream_info->lock, flags);
if (stream_cfg_cmd->cmd == START_STREAM) {
stream_info->bufq_handle =
@@ -379,6 +405,7 @@
sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
+ sof_event.mono_timestamp = ts->buf_time;
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
@@ -548,7 +575,8 @@
if (stream_info->state == INACTIVE)
return;
for (i = 0; i < stream_info->num_planes; i++) {
- if (stream_info->state == START_PENDING)
+ if (stream_info->state == START_PENDING ||
+ stream_info->state == RESUME_PENDING)
vfe_dev->hw_info->vfe_ops.axi_ops.
enable_wm(vfe_dev, stream_info->wm[i], 1);
else
@@ -558,7 +586,7 @@
if (stream_info->state == START_PENDING)
axi_data->num_active_stream++;
- else
+ else if (stream_info->state == STOP_PENDING)
axi_data->num_active_stream--;
}
@@ -594,6 +622,60 @@
complete(&vfe_dev->stream_config_complete);
}
+static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream *stream_info)
+{
+ int i, j;
+ uint32_t flag;
+ struct msm_isp_buffer *buf;
+ for (i = 0; i < 2; i++) {
+ buf = stream_info->buf[i];
+ flag = i ? VFE_PONG_FLAG : VFE_PING_FLAG;
+ for (j = 0; j < stream_info->num_planes; j++) {
+ vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
+ vfe_dev, stream_info->wm[j], flag,
+ buf->mapped_info[j].paddr +
+ stream_info->plane_cfg[j].plane_addr_offset);
+ }
+ }
+}
+
+void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev)
+{
+ int i, j;
+ uint32_t update_state;
+ unsigned long flags;
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ struct msm_vfe_axi_stream *stream_info;
+ for (i = 0; i < MAX_NUM_STREAM; i++) {
+ stream_info = &axi_data->stream_info[i];
+ if (stream_info->stream_type == BURST_STREAM ||
+ stream_info->state == AVALIABLE)
+ continue;
+ spin_lock_irqsave(&stream_info->lock, flags);
+ if (stream_info->state == PAUSING) {
+ /*AXI Stopped, apply update*/
+ stream_info->state = PAUSED;
+ msm_isp_reload_ping_pong_offset(vfe_dev, stream_info);
+ for (j = 0; j < stream_info->num_planes; j++)
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ cfg_wm_reg(vfe_dev, stream_info, j);
+ /*Resume AXI*/
+ stream_info->state = RESUME_PENDING;
+ msm_isp_axi_stream_enable_cfg(
+ vfe_dev, &axi_data->stream_info[i]);
+ stream_info->state = RESUMING;
+ } else if (stream_info->state == RESUMING) {
+ stream_info->runtime_output_format =
+ stream_info->output_format;
+ stream_info->state = ACTIVE;
+ }
+ spin_unlock_irqrestore(&stream_info->lock, flags);
+ }
+
+ update_state = atomic_dec_return(&axi_data->axi_cfg_update);
+}
+
static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
@@ -690,6 +772,8 @@
buf_event.u.buf_done.handle =
stream_info->bufq_handle;
buf_event.u.buf_done.buf_idx = buf->buf_idx;
+ buf_event.u.buf_done.output_format =
+ stream_info->runtime_output_format;
msm_isp_send_event(vfe_dev,
ISP_EVENT_BUF_DIVERT + stream_idx,
&buf_event);
@@ -697,7 +781,8 @@
} else {
vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
buf->bufq_handle, buf->buf_idx,
- &ts->buf_time, frame_id);
+ &ts->buf_time, frame_id,
+ stream_info->runtime_output_format);
}
}
}
@@ -745,7 +830,7 @@
&axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
if (stream_info->stream_src >= RDI_INTF_0)
- return;
+ continue;
if (stream_info->stream_src == PIX_ENCODER ||
stream_info->stream_src == PIX_VIEWFINDER ||
stream_info->stream_src == IDEAL_RAW) {
@@ -954,10 +1039,11 @@
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
- if (camif_update == ENABLE_CAMIF)
+ if (camif_update == ENABLE_CAMIF) {
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0;
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, camif_update);
-
+ }
if (wait_for_complete)
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
@@ -1045,40 +1131,87 @@
int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0;
+ int rc = 0, i, j;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
- stream_info = &axi_data->stream_info[
- HANDLE_TO_IDX(update_cmd->stream_handle)];
- if (stream_info->state != ACTIVE && stream_info->state != INACTIVE) {
- pr_err("%s: Invalid stream state\n", __func__);
- return -EINVAL;
+ struct msm_vfe_axi_stream_cfg_update_info *update_info;
+
+ if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG &&
+ atomic_read(&axi_data->axi_cfg_update)) {
+ pr_err("%s: AXI stream config updating\n", __func__);
+ return -EBUSY;
}
- switch (update_cmd->update_type) {
- case ENABLE_STREAM_BUF_DIVERT:
- stream_info->buf_divert = 1;
- break;
- case DISABLE_STREAM_BUF_DIVERT:
- stream_info->buf_divert = 0;
- vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr,
- stream_info->bufq_handle,
- MSM_ISP_BUFFER_FLUSH_DIVERTED);
- break;
- case UPDATE_STREAM_FRAMEDROP_PATTERN: {
- uint32_t framedrop_period =
- msm_isp_get_framedrop_period(update_cmd->skip_pattern);
- stream_info->runtime_init_frame_drop = 0;
- stream_info->framedrop_pattern = 0x1;
- stream_info->framedrop_period = framedrop_period - 1;
- vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_framedrop(vfe_dev, stream_info);
- break;
+ for (i = 0; i < update_cmd->num_streams; i++) {
+ update_info = &update_cmd->update_info[i];
+ stream_info = &axi_data->stream_info[
+ HANDLE_TO_IDX(update_info->stream_handle)];
+ if (stream_info->state != ACTIVE &&
+ stream_info->state != INACTIVE) {
+ pr_err("%s: Invalid stream state\n", __func__);
+ return -EINVAL;
+ }
+ if (stream_info->state == ACTIVE &&
+ stream_info->stream_type == BURST_STREAM) {
+ pr_err("%s: Cannot update active burst stream\n",
+ __func__);
+ return -EINVAL;
+ }
}
- default:
- pr_err("%s: Invalid update type\n", __func__);
- return -EINVAL;
+
+ for (i = 0; i < update_cmd->num_streams; i++) {
+ update_info = &update_cmd->update_info[i];
+ stream_info = &axi_data->stream_info[
+ HANDLE_TO_IDX(update_info->stream_handle)];
+
+ switch (update_cmd->update_type) {
+ case ENABLE_STREAM_BUF_DIVERT:
+ stream_info->buf_divert = 1;
+ break;
+ case DISABLE_STREAM_BUF_DIVERT:
+ stream_info->buf_divert = 0;
+ vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr,
+ stream_info->bufq_handle,
+ MSM_ISP_BUFFER_FLUSH_DIVERTED);
+ break;
+ case UPDATE_STREAM_FRAMEDROP_PATTERN: {
+ uint32_t framedrop_period =
+ msm_isp_get_framedrop_period(
+ update_info->skip_pattern);
+ stream_info->runtime_init_frame_drop = 0;
+ stream_info->framedrop_pattern = 0x1;
+ stream_info->framedrop_period = framedrop_period - 1;
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ cfg_framedrop(vfe_dev, stream_info);
+ break;
+ }
+ case UPDATE_STREAM_AXI_CONFIG: {
+ for (j = 0; j < stream_info->num_planes; j++) {
+ stream_info->plane_cfg[j] =
+ update_info->plane_cfg[j];
+ }
+ stream_info->output_format = update_info->output_format;
+ if (stream_info->state == ACTIVE) {
+ stream_info->state = PAUSE_PENDING;
+ msm_isp_axi_stream_enable_cfg(
+ vfe_dev, stream_info);
+ stream_info->state = PAUSING;
+ atomic_set(&axi_data->axi_cfg_update,
+ UPDATE_REQUESTED);
+ } else {
+ for (j = 0; j < stream_info->num_planes; j++)
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ cfg_wm_reg(vfe_dev, stream_info, j);
+ stream_info->runtime_output_format =
+ stream_info->output_format;
+ }
+ break;
+ }
+ default:
+ pr_err("%s: Invalid update type\n", __func__);
+ return -EINVAL;
+ }
}
return rc;
}
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 3d775f9..7d282bd 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
@@ -41,6 +41,7 @@
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg);
+void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev);
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
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 ee205c0..ac44c61 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
@@ -647,6 +647,8 @@
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
val = CAL_WORD(pixel_per_line, 1, 8);
@@ -691,6 +693,8 @@
return 12;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
return 8;
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 5581723..27aba5c 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -455,6 +455,9 @@
{
struct msm_command_ack *cmd_ack = d1;
+ if (!(&cmd_ack->command_q))
+ return 0;
+
msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
return 0;
@@ -462,7 +465,7 @@
static void msm_remove_session_cmd_ack_q(struct msm_session *session)
{
- if (!session)
+ if ((!session) || !(&session->command_ack_q))
return;
/* to ensure error handling purpose, it needs to detach all subdevs
@@ -492,6 +495,22 @@
return 0;
}
+static int __msm_close_destry_session_notify_apps(void *d1, void *d2)
+{
+ struct v4l2_event event;
+ struct msm_v4l2_event_data *event_data =
+ (struct msm_v4l2_event_data *)&event.u.data[0];
+ struct msm_session *session = d1;
+
+ 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);
+
+ return 0;
+}
+
static long msm_private_ioctl(struct file *file, void *fh,
bool valid_prio, int cmd, void *arg)
{
@@ -551,6 +570,13 @@
}
break;
+ case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR:
+ /* send v4l2_event to HAL next*/
+ msm_queue_traverse_action(msm_session_q,
+ struct msm_session, list,
+ __msm_close_destry_session_notify_apps, NULL);
+ break;
+
default:
rc = -ENOTTY;
break;
@@ -678,22 +704,6 @@
return rc;
}
-static int __msm_close_destry_session_notify_apps(void *d1, void *d2)
-{
- struct v4l2_event event;
- struct msm_v4l2_event_data *event_data =
- (struct msm_v4l2_event_data *)&event.u.data[0];
- struct msm_session *session = d1;
-
- 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);
-
- return 0;
-}
-
static int msm_close(struct file *filep)
{
int rc = 0;
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 895f452..154ee87 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
@@ -62,6 +62,7 @@
(bufs->vb2_buf->v4l2_buf.index == buf_info->index)) {
bufs->vb2_buf->v4l2_buf.sequence = buf_info->frame_id;
bufs->vb2_buf->v4l2_buf.timestamp = buf_info->timestamp;
+ bufs->vb2_buf->v4l2_buf.reserved = 0;
ret = buf_mngr_dev->vb2_ops.buf_done
(bufs->vb2_buf,
buf_info->session_id,
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 4dd3f3d..4f02197 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
@@ -741,10 +741,14 @@
if (NULL != fw)
ptr_bin = (uint32_t *)fw->data;
- for (i = 0; i < fw->size/4; i++) {
- if (ptr_bin) {
- msm_cpp_write(*ptr_bin, cpp_dev->base);
- ptr_bin++;
+ if (ptr_bin == NULL) {
+ pr_err("ptr_bin is NULL\n");
+ } else {
+ for (i = 0; i < fw->size/4; i++) {
+ if (ptr_bin) {
+ msm_cpp_write(*ptr_bin, cpp_dev->base);
+ ptr_bin++;
+ }
}
}
if (fw)
@@ -1172,6 +1176,11 @@
int rc = 0;
char *fw_name_bin;
+ if (ioctl_ptr == NULL) {
+ pr_err("ioctl_ptr is null\n");
+ return -EINVAL;
+ }
+
mutex_lock(&cpp_dev->mutex);
CPP_DBG("E cmd: %d\n", cmd);
switch (cmd) {
@@ -1187,7 +1196,7 @@
case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
if (cpp_dev->is_firmware_loaded == 0) {
- fw_name_bin = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ fw_name_bin = kzalloc(ioctl_ptr->len+1, GFP_KERNEL);
if (!fw_name_bin) {
pr_err("%s:%d: malloc error\n", __func__,
__LINE__);
@@ -1195,6 +1204,14 @@
return -EINVAL;
}
+ if (ioctl_ptr->ioctl_ptr == NULL) {
+ pr_err("ioctl_ptr->ioctl_ptr=NULL\n");
+ return -EINVAL;
+ }
+ if (ioctl_ptr->len == 0) {
+ pr_err("ioctl_ptr->len is 0\n");
+ return -EINVAL;
+ }
rc = (copy_from_user(fw_name_bin,
(void __user *)ioctl_ptr->ioctl_ptr,
ioctl_ptr->len) ? -EFAULT : 0);
@@ -1204,6 +1221,11 @@
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
+ *(fw_name_bin+ioctl_ptr->len) = '\0';
+ if (cpp_dev == NULL) {
+ pr_err("cpp_dev is null\n");
+ return -EINVAL;
+ }
disable_irq(cpp_dev->irq->start);
cpp_load_fw(cpp_dev, fw_name_bin);
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 b115738..300daca 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
@@ -435,6 +435,8 @@
return -EFAULT;
}
+ kfree(a_ctrl->i2c_reg_tbl);
+
a_ctrl->i2c_reg_tbl =
kmalloc(sizeof(struct msm_camera_i2c_reg_tbl) *
(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
@@ -608,6 +610,9 @@
if (rc < 0)
pr_err("cci_init failed\n");
}
+ kfree(a_ctrl->i2c_reg_tbl);
+ a_ctrl->i2c_reg_tbl = NULL;
+
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 f3da41c..676862f 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
@@ -307,10 +307,10 @@
}
if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
- val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
+ val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
((read_cfg->addr & 0xFF) << 8);
if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR)
- val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
+ val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
(((read_cfg->addr & 0xFF00) >> 8) << 8) |
((read_cfg->addr & 0xFF) << 16);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
@@ -714,40 +714,40 @@
complete(&cci_dev->cci_master_info[MASTER_1].
reset_complete);
}
- } else if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) ||
+ }
+ if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK)) {
cci_dev->cci_master_info[MASTER_0].status = 0;
complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
- } else if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) ||
+ }
+ if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) {
cci_dev->cci_master_info[MASTER_1].status = 0;
complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
- } else if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
+ }
+ if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
msm_camera_io_w(CCI_M0_RESET_RMSK,
cci_dev->base + CCI_RESET_CMD_ADDR);
- } else if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) {
+ }
+ if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
msm_camera_io_w(CCI_M1_RESET_RMSK,
cci_dev->base + CCI_RESET_CMD_ADDR);
- } else if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
+ }
+ if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
pr_err("%s:%d MASTER_0 error %x\n", __func__, __LINE__, irq);
cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
msm_camera_io_w(CCI_M0_HALT_REQ_RMSK,
cci_dev->base + CCI_HALT_REQ_ADDR);
- } else if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
+ }
+ if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
pr_err("%s:%d MASTER_1 error %x\n", __func__, __LINE__, irq);
cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
msm_camera_io_w(CCI_M1_HALT_REQ_RMSK,
cci_dev->base + CCI_HALT_REQ_ADDR);
- } else {
- pr_err("%s unhandled irq 0x%x\n", __func__, irq);
- cci_dev->cci_master_info[MASTER_0].status = 0;
- complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
- cci_dev->cci_master_info[MASTER_1].status = 0;
- complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
}
return IRQ_HANDLED;
}
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 d56a5252..68c7d23 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -616,7 +616,7 @@
static int32_t msm_sensor_get_dt_data(struct platform_device *pdev,
struct msm_sensor_ctrl_t *s_ctrl)
{
- int32_t rc = 0, i = 0;
+ int32_t rc = 0, i = 0, ret = 0;
struct device_node *of_node = pdev->dev.of_node;
struct msm_camera_gpio_conf *gconf = NULL;
struct msm_camera_sensor_board_info *sensordata = NULL;
@@ -777,14 +777,11 @@
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",
+ /*Optional property, don't return error if absent */
+ ret = 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;
- }
+ sensordata->misc_regulator, ret);
kfree(gpio_array);
@@ -1155,6 +1152,7 @@
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;
@@ -1257,6 +1255,7 @@
power_setting_array->size *
sizeof(struct msm_sensor_power_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(power_setting_array->power_setting);
rc = -EFAULT;
break;
}
@@ -1325,6 +1324,127 @@
kfree(reg_setting);
break;
}
+ case CFG_SLAVE_READ_I2C: {
+ struct msm_camera_i2c_read_config read_config;
+ uint16_t local_data = 0;
+ uint16_t orig_slave_addr = 0, read_slave_addr = 0;
+ if (copy_from_user(&read_config,
+ (void *)cdata->cfg.setting,
+ sizeof(struct msm_camera_i2c_read_config))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ read_slave_addr = read_config.slave_addr;
+ CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
+ CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
+ __func__, read_config.slave_addr,
+ read_config.reg_addr, read_config.data_type);
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->cci_client->sid;
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ read_slave_addr >> 1;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->client->addr;
+ s_ctrl->sensor_i2c_client->client->addr =
+ read_slave_addr >> 1;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+ __func__, orig_slave_addr,
+ read_slave_addr >> 1);
+ rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+ s_ctrl->sensor_i2c_client,
+ read_config.reg_addr,
+ &local_data, read_config.data_type);
+ if (rc < 0) {
+ pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
+ break;
+ }
+ if (copy_to_user((void __user *)read_config.data,
+ (void *)&local_data, sizeof(uint16_t))) {
+ pr_err("%s:%d copy failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case CFG_SLAVE_WRITE_I2C_ARRAY: {
+ struct msm_camera_i2c_array_write_config write_config;
+ struct msm_camera_i2c_reg_array *reg_setting = NULL;
+ uint16_t write_slave_addr = 0;
+ uint16_t orig_slave_addr = 0;
+
+ if (copy_from_user(&write_config,
+ (void *)cdata->cfg.setting,
+ sizeof(struct msm_camera_i2c_array_write_config))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__);
+ CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
+ write_config.slave_addr,
+ write_config.conf_array.size);
+ reg_setting = kzalloc(write_config.conf_array.size *
+ (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+ if (!reg_setting) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(reg_setting,
+ (void *)(write_config.conf_array.reg_setting),
+ write_config.conf_array.size *
+ sizeof(struct msm_camera_i2c_reg_array))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ write_config.conf_array.reg_setting = reg_setting;
+ write_slave_addr = write_config.slave_addr;
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->cci_client->sid;
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ write_slave_addr >> 1;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->client->addr;
+ s_ctrl->sensor_i2c_client->client->addr =
+ write_slave_addr >> 1;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+ __func__, orig_slave_addr,
+ write_slave_addr >> 1);
+ rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+ s_ctrl->sensor_i2c_client, &(write_config.conf_array));
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ orig_slave_addr;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ s_ctrl->sensor_i2c_client->client->addr =
+ orig_slave_addr;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ kfree(reg_setting);
+ break;
+ }
case CFG_WRITE_I2C_SEQ_ARRAY: {
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
@@ -1395,6 +1515,8 @@
break;
case CFG_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);
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 d07387e..a63fccf 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
@@ -4055,11 +4055,13 @@
pes_event.pes_end.start_gap = 0;
pes_event.data_length = 0;
- /* Parse error indicators - TODO: these should be per filter */
+ /* Parse error indicators */
if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN)
pes_event.pes_end.pes_length_mismatch = 1;
- if (sts->error_indicators & SDMX_FILTER_ERR_CONT_CNT_INVALID)
- pes_event.pes_end.disc_indicator_set = 0;
+ else
+ pes_event.pes_end.pes_length_mismatch = 0;
+
+ pes_event.pes_end.disc_indicator_set = 0;
pes_event.pes_end.stc = 0;
pes_event.pes_end.tei_counter = counters.transport_err_count;
@@ -4109,7 +4111,7 @@
MPQ_DVB_DBG_PRINT("%s: Notify CRC err event\n", __func__);
event.status = DMX_CRC_ERROR;
event.data_length = 0;
- feed->data_ready_cb.sec(&feed->filter->filter, &event);
+ dvb_dmx_notify_section_event(feed, &event, 1);
}
if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
@@ -4143,12 +4145,7 @@
if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
event.data_length = 0;
event.status = DMX_OK_EOS;
- f = feed->filter;
-
- while (f && sec->is_filtering) {
- feed->data_ready_cb.sec(&f->filter, &event);
- f = f->next;
- }
+ dvb_dmx_notify_section_event(feed, &event, 1);
}
}
@@ -4469,10 +4466,12 @@
{
int i;
int j;
+ int sdmx_filters;
struct sdmx_filter_status *sts;
struct mpq_feed *mpq_feed;
- for (i = 0; i < mpq_demux->sdmx_filter_count; i++) {
+ sdmx_filters = mpq_demux->sdmx_filter_count;
+ for (i = 0; i < sdmx_filters; i++) {
/*
* MPQ_TODO: review lookup optimization
* Can have the related mpq_feed index already associated with
@@ -4815,21 +4814,11 @@
event.status = DMX_OK_MARKER;
event.marker.id = cmd->params.marker.id;
- if (feed->type == DMX_TYPE_SEC) {
- struct dvb_demux_filter *f = feed->filter;
- struct dmx_section_feed *sec = &feed->feed.sec;
-
- while (f && sec->is_filtering) {
- ret = feed->data_ready_cb.sec(&f->filter,
- &event);
- if (ret)
- break;
- f = f->next;
- }
- } else {
+ if (feed->type == DMX_TYPE_SEC)
+ ret = dvb_dmx_notify_section_event(feed, &event, 1);
+ else
/* MPQ_TODO: Notify decoder via the stream buffer */
ret = feed->data_ready_cb.ts(&feed->feed.ts, &event);
- }
break;
default:
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 42d4f95..6e8c809 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -61,6 +61,18 @@
[ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
};
+static int nal_type[] = {
+ [ilog2(HAL_NAL_FORMAT_STARTCODES)] = HFI_NAL_FORMAT_STARTCODES,
+ [ilog2(HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER)] =
+ HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER,
+ [ilog2(HAL_NAL_FORMAT_ONE_BYTE_LENGTH)] =
+ HFI_NAL_FORMAT_ONE_BYTE_LENGTH,
+ [ilog2(HAL_NAL_FORMAT_TWO_BYTE_LENGTH)] =
+ HFI_NAL_FORMAT_TWO_BYTE_LENGTH,
+ [ilog2(HAL_NAL_FORMAT_FOUR_BYTE_LENGTH)] =
+ HFI_NAL_FORMAT_FOUR_BYTE_LENGTH,
+};
+
static inline int hal_to_hfi_type(int property, int hal_type)
{
if (hal_type && (roundup_pow_of_two(hal_type) != hal_type)) {
@@ -85,6 +97,9 @@
case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
return (hal_type >= ARRAY_SIZE(color_format)) ?
-ENOTSUPP : color_format[hal_type];
+ case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+ return (hal_type >= ARRAY_SIZE(nal_type)) ?
+ -ENOTSUPP : nal_type[hal_type];
default:
return -ENOTSUPP;
}
@@ -717,40 +732,20 @@
}
case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
{
- struct hal_nal_stream_format_supported *prop =
- (struct hal_nal_stream_format_supported *)pdata;
+ struct hfi_nal_stream_format_select *hfi;
+ struct hal_nal_stream_format_select *prop =
+ (struct hal_nal_stream_format_select *)pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
+ hfi = (struct hfi_nal_stream_format_select *)
+ &pkt->rg_property_data[1];
dprintk(VIDC_DBG, "data is :%d",
- prop->nal_stream_format_supported);
-
- switch (prop->nal_stream_format_supported) {
- case HAL_NAL_FORMAT_STARTCODES:
- pkt->rg_property_data[1] =
- HFI_NAL_FORMAT_STARTCODES;
- break;
- case HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER:
- pkt->rg_property_data[1] =
- HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER;
- break;
- case HAL_NAL_FORMAT_ONE_BYTE_LENGTH:
- pkt->rg_property_data[1] =
- HFI_NAL_FORMAT_ONE_BYTE_LENGTH;
- break;
- case HAL_NAL_FORMAT_TWO_BYTE_LENGTH:
- pkt->rg_property_data[1] =
- HFI_NAL_FORMAT_TWO_BYTE_LENGTH;
- break;
- case HAL_NAL_FORMAT_FOUR_BYTE_LENGTH:
- pkt->rg_property_data[1] =
- HFI_NAL_FORMAT_FOUR_BYTE_LENGTH;
- break;
- default:
- dprintk(VIDC_ERR, "Invalid nal format: 0x%x",
- prop->nal_stream_format_supported);
- break;
- }
- pkt->size += sizeof(u32) * 2;
+ prop->nal_stream_format_select);
+ hfi->nal_stream_format_select = hal_to_hfi_type(
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+ prop->nal_stream_format_select);
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_nal_stream_format_select);
break;
}
case HAL_PARAM_VDEC_OUTPUT_ORDER:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 19f5dcd..859345f 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -676,7 +676,7 @@
{
struct msm_vidc_cb_cmd_done cmd_done;
struct vidc_hal_session_init_done session_init_done;
-
+ struct hal_session *sess_close = NULL;
dprintk(VIDC_DBG, "RECEIVED:SESSION_INIT_DONE");
if (sizeof(struct hfi_msg_sys_session_init_done_packet)
> pkt->size) {
@@ -696,6 +696,16 @@
if (!cmd_done.status) {
cmd_done.status = hfi_process_sess_init_done_prop_read(
pkt, &session_init_done);
+ } else {
+ sess_close = (struct hal_session *)pkt->session_id;
+ if (sess_close) {
+ dprintk(VIDC_INFO,
+ "Sess init failed: Deleting session: 0x%x 0x%p",
+ sess_close->session_id, sess_close);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ sess_close = NULL;
+ }
}
cmd_done.size = sizeof(struct vidc_hal_session_init_done);
callback(SESSION_INIT_DONE, &cmd_done);
@@ -1015,6 +1025,7 @@
sess_close->session_id);
list_del(&sess_close->list);
kfree(sess_close);
+ sess_close = NULL;
callback(SESSION_END_DONE, &cmd_done);
}
@@ -1050,6 +1061,7 @@
sess_close->session_id);
list_del(&sess_close->list);
kfree(sess_close);
+ sess_close = NULL;
callback(SESSION_ABORT_DONE, &cmd_done);
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 1885379..7547464 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -69,6 +69,12 @@
"Extradata mpeg2 seqdisp",
};
+static const char *const perf_level[] = {
+ "Nominal",
+ "Performance",
+ "Turbo"
+};
+
static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
@@ -230,6 +236,19 @@
.qmenu = mpeg_video_vidc_extradata,
.step = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+ .name = "Encoder Performance Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+ .default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+ .qmenu = perf_level,
+ .step = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -700,7 +719,7 @@
int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
{
u64 us_per_frame = 0;
- int rc = 0, fps = 0, rem = 0;
+ int rc = 0, fps = 0;
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
@@ -726,17 +745,20 @@
}
fps = USEC_PER_SEC;
- rem = do_div(fps, us_per_frame);
- if (rem) {
- /* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
- fps++;
- }
+ do_div(fps, us_per_frame);
+
+ if ((fps % 15 == 14) || (fps % 24 == 23))
+ fps = fps + 1;
+ else if ((fps % 24 == 1) || (fps % 15 == 1))
+ fps = fps - 1;
if (inst->prop.fps != fps) {
dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
inst, inst->prop.fps, fps);
inst->prop.fps = fps;
+ mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
+ mutex_unlock(&inst->core->sync_lock);
}
exit:
return rc;
@@ -960,6 +982,7 @@
"No buffer requirement for buffer type %x\n",
HAL_BUFFER_OUTPUT);
rc = -EINVAL;
+ mutex_unlock(&inst->lock);
break;
}
if (*num_buffers && *num_buffers >
@@ -1021,7 +1044,11 @@
"Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
+
+ mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
+ mutex_unlock(&inst->core->sync_lock);
+
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
dprintk(VIDC_ERR,
@@ -1112,7 +1139,10 @@
rc = -EINVAL;
break;
}
+
+ mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
+ mutex_unlock(&inst->core->sync_lock);
if (rc)
dprintk(VIDC_ERR,
@@ -1132,7 +1162,6 @@
int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
{
int rc = 0;
- struct v4l2_event dqevent = {0};
struct msm_vidc_core *core = inst->core;
if (!dec || !inst || !inst->core) {
@@ -1164,16 +1193,15 @@
dprintk(VIDC_ERR,
"Core %p in bad state, Sending CLOSE event\n",
core);
- dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
goto exit;
}
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
/* Clients rely on this event for joining poll thread.
* This event should be returned even if firmware has
* failed to respond */
- dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
break;
default:
dprintk(VIDC_ERR, "Unknown Decoder Command\n");
@@ -1223,14 +1251,12 @@
static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
- struct v4l2_control control;
struct hal_nal_stream_format_supported stream_format;
struct hal_enable_picture enable_picture;
struct hal_enable hal_property;/*, prop;*/
- u32 control_idx = 0;
enum hal_property property_id = 0;
u32 property_val = 0;
- void *pdata;
+ void *pdata = NULL;
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
@@ -1294,8 +1320,9 @@
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
- inst->mode = VIDC_SECURE;
- dprintk(VIDC_DBG, "Setting secure mode to :%d\n", inst->mode);
+ inst->flags |= VIDC_SECURE;
+ dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
+ !!(inst->flags & VIDC_SECURE));
break;
case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
{
@@ -1306,16 +1333,30 @@
pdata = &extra;
break;
}
+ case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+ inst->flags &= ~VIDC_TURBO;
+ break;
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+ inst->flags |= VIDC_TURBO;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Perf mode %x not supported",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ break;
default:
break;
}
if (!rc && property_id) {
dprintk(VIDC_DBG,
- "Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
- property_id,
- msm_vdec_ctrls[control_idx].id,
- control.value);
+ "Control: HAL property = %d, ctrl_id = 0x%x, ctrl_value = %d\n",
+ property_id, ctrl->id, ctrl->val);
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, property_id, pdata);
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c3cfe76..7fc2595 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -21,7 +21,7 @@
#define MSM_VENC_DVC_NAME "msm_venc_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MIN_NUM_CAPTURE_BUFFERS 4
-#define MIN_BIT_RATE 64000
+#define MIN_BIT_RATE 32000
#define MAX_BIT_RATE 160000000
#define DEFAULT_BIT_RATE 64000
#define BIT_RATE_STEP 100
@@ -108,6 +108,12 @@
"Extradata aspect ratio",
};
+static const char *const perf_level[] = {
+ "Nominal",
+ "Performance",
+ "Turbo"
+};
+
enum msm_venc_ctrl_cluster {
MSM_VENC_CTRL_CLUSTER_QP = 1 << 0,
MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD = 1 << 1,
@@ -124,18 +130,6 @@
static struct msm_vidc_ctrl msm_venc_ctrls[] = {
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
- .name = "Frame Rate",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = MIN_FRAME_RATE,
- .maximum = MAX_FRAME_RATE,
- .default_value = MIN_FRAME_RATE,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- .cluster = MSM_VENC_CTRL_CLUSTER_TIMING,
- },
- {
.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
.name = "IDR Period",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -676,6 +670,19 @@
.default_value =
V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+ .name = "Encoder Performance Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+ .default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+ (1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+ .qmenu = perf_level,
+ .step = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -871,7 +878,10 @@
dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
+
+ mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
+ mutex_unlock(&inst->core->sync_lock);
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
@@ -947,7 +957,10 @@
rc = -EINVAL;
break;
}
+
+ mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
+ mutex_unlock(&inst->core->sync_lock);
if (rc)
dprintk(VIDC_ERR,
@@ -1154,7 +1167,6 @@
static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
- struct hal_frame_rate frame_rate;
struct hal_request_iframe request_iframe;
struct hal_bitrate bitrate;
struct hal_profile_level profile_level;
@@ -1196,13 +1208,6 @@
})
switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
- property_id =
- HAL_CONFIG_FRAME_RATE;
- frame_rate.frame_rate = ctrl->val;
- frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
- pdata = &frame_rate;
- break;
case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
property_id =
HAL_CONFIG_VENC_IDR_PERIOD;
@@ -1716,8 +1721,9 @@
pdata = &enable;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
- inst->mode = VIDC_SECURE;
- dprintk(VIDC_INFO, "Setting secure mode to :%d\n", inst->mode);
+ inst->flags |= VIDC_SECURE;
+ dprintk(VIDC_INFO, "Setting secure mode to: %d\n",
+ !!(inst->flags & VIDC_SECURE));
break;
case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
{
@@ -1730,12 +1736,11 @@
}
case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
{
- struct v4l2_ctrl *rc_mode, *frame_rate;
+ struct v4l2_ctrl *rc_mode;
bool cfr = false;
property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
- frame_rate = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE);
switch (rc_mode->val) {
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
@@ -1752,20 +1757,9 @@
vui_timing_info.enable = 0;
break;
case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
- /* Only support this in CFR mode because we
- * don't really know how to fill out vui_timing_info.
- * time_scale in vfr mode. The assumed framerate
- * might be incorrect. */
- if (!cfr) {
- dprintk(VIDC_ERR, "Can't set %x in VFR mode\n",
- ctrl->id);
- rc = -ENOTSUPP;
- break;
- }
-
vui_timing_info.enable = 1;
vui_timing_info.fixed_frame_rate = cfr;
- vui_timing_info.time_scale = frame_rate->val;
+ vui_timing_info.time_scale = inst->prop.fps;
}
pdata = &vui_timing_info;
@@ -1788,6 +1782,22 @@
pdata = &enable;
break;
+ case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+ switch (ctrl->val) {
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+ inst->flags &= ~VIDC_TURBO;
+ break;
+ case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+ inst->flags |= VIDC_TURBO;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Perf mode %x not supported",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+
+ break;
default:
rc = -ENOTSUPP;
break;
@@ -1881,7 +1891,6 @@
int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
{
int rc = 0;
- struct v4l2_event dqevent = {0};
struct msm_vidc_core *core;
core = inst->core;
switch (enc->cmd) {
@@ -1891,8 +1900,8 @@
case V4L2_ENC_CMD_STOP:
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
- dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
return rc;
}
rc = msm_comm_release_scratch_buffers(inst);
@@ -1907,8 +1916,7 @@
/* Clients rely on this event for joining poll thread.
* This event should be returned even if firmware has
* failed to respond */
- dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
break;
}
if (rc)
@@ -1969,7 +1977,7 @@
{
u32 property_id = 0, us_per_frame = 0;
void *pdata;
- int rc = 0, fps = 0, rem = 0;
+ int rc = 0, fps = 0;
struct hal_frame_rate frame_rate;
struct hfi_device *hdev;
@@ -2006,11 +2014,12 @@
}
fps = USEC_PER_SEC;
- rem = do_div(fps, us_per_frame);
- if (rem) {
- /* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
- fps++;
- }
+ do_div(fps, us_per_frame);
+
+ if ((fps % 15 == 14) || (fps % 24 == 23))
+ fps = fps + 1;
+ else if ((fps % 24 == 1) || (fps % 15 == 1))
+ fps = fps - 1;
if (inst->prop.fps != fps) {
dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
@@ -2026,7 +2035,9 @@
dprintk(VIDC_WARN,
"Failed to set frame rate %d\n", rc);
}
+ mutex_lock(&inst->core->sync_lock);
msm_comm_scale_clocks_and_bus(inst);
+ mutex_unlock(&inst->core->sync_lock);
}
exit:
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 91fcdb6..bd05180 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -46,6 +46,28 @@
u32 __mbs = (__h >> 4) * (__w >> 4);\
__mbs;\
})
+static bool is_turbo_requested(struct msm_vidc_core *core,
+ enum session_type type)
+{
+ struct msm_vidc_inst *inst = NULL;
+
+ list_for_each_entry(inst, &core->instances, list) {
+ bool wants_turbo = false;
+
+ mutex_lock(&inst->lock);
+ if (inst->session_type == type &&
+ inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_STOP_DONE) {
+ wants_turbo = inst->flags & VIDC_TURBO;
+ }
+ mutex_unlock(&inst->lock);
+
+ if (wants_turbo)
+ return true;
+ }
+
+ return false;
+}
static int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type)
@@ -61,29 +83,8 @@
if (inst->session_type == type &&
inst->state >= MSM_VIDC_OPEN_DONE &&
inst->state < MSM_VIDC_STOP_DONE) {
- int stride, scanlines, rc;
- struct hfi_device *hdev;
-
- hdev = inst->core->device;
- if (!hdev) {
- dprintk(VIDC_ERR,
- "No hdev (probably in bad state)\n");
- return -EINVAL;
- }
-
- rc = call_hfi_op(hdev, get_stride_scanline,
- COLOR_FMT_NV12,
- inst->prop.width, inst->prop.height,
- &stride, &scanlines);
- if (rc) {
- dprintk(VIDC_WARN,
- "Failed to determine stride/scan when getting load. Perf. might be affected\n");
- stride = inst->prop.width;
- scanlines = inst->prop.height;
- }
-
- num_mbs_per_sec += NUM_MBS_PER_SEC(stride, scanlines,
- inst->prop.fps);
+ num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
+ inst->prop.width, inst->prop.fps);
}
mutex_unlock(&inst->lock);
}
@@ -108,7 +109,10 @@
return -EINVAL;
}
- load = msm_comm_get_load(core, type);
+ if (is_turbo_requested(core, type))
+ load = core->resources.max_load;
+ else
+ load = msm_comm_get_load(core, type);
rc = call_hfi_op(hdev, scale_bus, hdev->hfi_device_data,
load, type, mtype);
@@ -307,10 +311,21 @@
static void change_inst_state(struct msm_vidc_inst *inst,
enum instance_state state)
{
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid parameter %s", __func__);
+ return;
+ }
mutex_lock(&inst->lock);
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_DBG,
+ "Inst: %p is in bad state can't change state",
+ inst);
+ goto exit;
+ }
dprintk(VIDC_DBG, "Moved inst: %p from state: %d to state: %d\n",
inst, inst->state, state);
inst->state = state;
+exit:
mutex_unlock(&inst->lock);
}
@@ -361,38 +376,64 @@
return rc;
}
-static void handle_session_init_done(enum command_response cmd, void *data)
-{
- struct msm_vidc_cb_cmd_done *response = data;
- struct msm_vidc_inst *inst;
- if (response && !response->status) {
- struct vidc_hal_session_init_done *session_init_done =
- (struct vidc_hal_session_init_done *) response->data;
- inst = (struct msm_vidc_inst *)response->session_id;
-
- inst->capability.width = session_init_done->width;
- inst->capability.height = session_init_done->height;
- inst->capability.frame_rate =
- session_init_done->frame_rate;
- inst->capability.capability_set = true;
- signal_session_msg_receipt(cmd, inst);
- } else {
- dprintk(VIDC_ERR,
- "Failed to get valid response for session init\n");
- }
-}
-
-static void queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
{
struct v4l2_event event = {.id = 0, .type = event_type};
v4l2_event_queue_fh(&inst->event_handler, &event);
wake_up(&inst->kernel_event_queue);
}
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
+ return;
+ }
+ mutex_lock(&inst->lock);
+ inst->session = NULL;
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ mutex_unlock(&inst->lock);
+}
+
+static void handle_session_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst = NULL;
+ if (response) {
+ struct vidc_hal_session_init_done *session_init_done =
+ (struct vidc_hal_session_init_done *)
+ response->data;
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters",
+ __func__);
+ return;
+ }
+ if (!response->status && session_init_done) {
+ inst->capability.width = session_init_done->width;
+ inst->capability.height = session_init_done->height;
+ inst->capability.frame_rate =
+ session_init_done->frame_rate;
+ inst->capability.capability_set = true;
+ } else {
+ dprintk(VIDC_ERR,
+ "Session init response from FW : 0x%x",
+ response->status);
+ msm_comm_generate_session_error(inst);
+ }
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for session init\n");
+ }
+}
+
static void handle_event_change(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
+ struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
int rc = 0;
@@ -401,7 +442,15 @@
event_notify = (struct msm_vidc_cb_event *) response->data;
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
- event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to get Smooth streamng flag\n");
+ if (!rc && control.value == true)
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
@@ -419,7 +468,7 @@
}
rc = msm_vidc_check_session_supported(inst);
if (!rc) {
- queue_v4l2_event(inst, event);
+ msm_vidc_queue_v4l2_event(inst, event);
}
return;
@@ -513,7 +562,7 @@
struct msm_vidc_inst *inst;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
} else {
dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
}
@@ -531,7 +580,8 @@
mutex_lock(&inst->sync_lock);
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->sync_lock);
- queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
} else {
dprintk(VIDC_ERR,
@@ -543,6 +593,10 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL ;
struct msm_vidc_core *core = NULL;
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ subsystem_crashed("venus");
if (response) {
core = get_vidc_core(response->device_id);
dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
@@ -554,9 +608,19 @@
list) {
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
+ if (inst->core)
+ hdev = inst->core->device;
+ if (hdev && inst->session) {
+ rc = call_hfi_op(hdev, session_clean,
+ (void *) inst->session);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Sess clean failed :%p",
+ inst);
+ }
+ inst->session = NULL;
mutex_unlock(&inst->lock);
-
- queue_v4l2_event(inst,
+ msm_vidc_queue_v4l2_event(inst,
V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
} else {
@@ -574,6 +638,8 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct msm_vidc_core *core = NULL;
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
dprintk(VIDC_ERR, "Venus Subsystem crashed\n");
core = get_vidc_core(response->device_id);
if (!core) {
@@ -586,9 +652,21 @@
mutex_unlock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
if (inst) {
- queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
+ if (inst->core)
+ hdev = inst->core->device;
+ if (hdev && inst->session) {
+ rc = call_hfi_op(hdev, session_clean,
+ (void *) inst->session);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Sess clean failed :%p",
+ inst);
+
+ }
inst->session = NULL;
mutex_unlock(&inst->lock);
}
@@ -705,6 +783,7 @@
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
break;
case HAL_PICTURE_I:
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
@@ -880,8 +959,14 @@
__func__, hdev);
return -EINVAL;
}
- num_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_ENCODER);
- num_mbs_per_sec += msm_comm_get_load(core, MSM_VIDC_DECODER);
+
+ if (is_turbo_requested(core, MSM_VIDC_ENCODER) ||
+ is_turbo_requested(core, MSM_VIDC_DECODER)) {
+ num_mbs_per_sec = core->resources.max_load;
+ } else {
+ num_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_ENCODER);
+ num_mbs_per_sec += msm_comm_get_load(core, MSM_VIDC_DECODER);
+ }
dprintk(VIDC_INFO, "num_mbs_per_sec = %d\n", num_mbs_per_sec);
rc = call_hfi_op(hdev, scale_clocks,
@@ -1202,9 +1287,11 @@
}
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
+ mutex_lock(&inst->lock);
inst->session = call_hfi_op(hdev, session_init, hdev->hfi_device_data,
(u32) inst, get_hal_domain(inst->session_type),
get_hal_codec_type(fourcc));
+ mutex_unlock(&inst->lock);
if (!inst->session) {
dprintk(VIDC_ERR,
"Failed to call session init for: %d, %d, %d, %d\n",
@@ -1230,6 +1317,12 @@
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
}
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core is in bad state can't do load res");
+ return -EINVAL;
+ }
num_mbs_per_sec = msm_comm_get_load(inst->core, MSM_VIDC_DECODER);
num_mbs_per_sec += msm_comm_get_load(inst->core, MSM_VIDC_ENCODER);
@@ -1304,6 +1397,12 @@
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
}
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Core is in bad state can't do start");
+ return -EINVAL;
+ }
hdev = inst->core->device;
@@ -1476,7 +1575,7 @@
scratch_buf->buffer_count_actual,
scratch_buf->buffer_size);
- if (inst->mode == VIDC_SECURE)
+ if (inst->flags & VIDC_SECURE)
smem_flags |= SMEM_SECURE;
if (scratch_buf->buffer_size) {
@@ -1564,7 +1663,7 @@
return rc;
}
- if (inst->mode == VIDC_SECURE)
+ if (inst->flags & VIDC_SECURE)
smem_flags |= SMEM_SECURE;
if (persist_buf->buffer_size) {
@@ -2177,7 +2276,8 @@
}
}
}
- queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
return;
}
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
@@ -2220,6 +2320,7 @@
"Core %p and inst %p are in bad state\n",
core, inst);
msm_comm_flush_in_invalid_state(inst);
+ return 0;
}
mutex_lock(&inst->sync_lock);
@@ -2382,7 +2483,6 @@
{
struct msm_vidc_core_capability *capability;
int rc = 0;
- struct v4l2_event dqevent;
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
@@ -2411,9 +2511,7 @@
mutex_lock(&inst->sync_lock);
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->sync_lock);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
wake_up(&inst->kernel_event_queue);
}
return rc;
@@ -2442,10 +2540,9 @@
dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
return -EINVAL;
}
- if (inst->state < MSM_VIDC_OPEN_DONE) {
+ if (!inst->session || inst->state < MSM_VIDC_OPEN_DONE) {
dprintk(VIDC_WARN,
"No corresponding FW session. No need to send Abort");
- inst->state = MSM_VIDC_CORE_INVALID;
return rc;
}
hdev = inst->core->device;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index ae1e9b7..bea9070 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -15,7 +15,8 @@
#include "vidc_hfi_api.h"
#define MAX_DBG_BUF_SIZE 4096
-int msm_vidc_debug = 0x3;
+int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+int msm_vidc_debug_out = VIDC_OUT_PRINTK;
int msm_fw_debug = 0x18;
int msm_fw_debug_mode = 0x1;
int msm_fw_low_power_mode = 0x1;
@@ -171,6 +172,11 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ if (!debugfs_create_u32("debug_output", S_IRUGO | S_IWUSR,
+ parent, &msm_vidc_debug_out)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
failed_create_dir:
return dir;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index ea6dd70..5b572c9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -31,9 +31,15 @@
VIDC_INFO = 0x0004,
VIDC_DBG = 0x0008,
VIDC_PROF = 0x0010,
+ VIDC_PKT = 0x0020,
VIDC_FW = 0x1000,
};
+enum vidc_msg_out {
+ VIDC_OUT_PRINTK = 0,
+ VIDC_OUT_FTRACE,
+};
+
enum msm_vidc_debugfs_event {
MSM_VIDC_DEBUGFS_EVENT_ETB,
MSM_VIDC_DEBUGFS_EVENT_EBD,
@@ -42,6 +48,7 @@
};
extern int msm_vidc_debug;
+extern int msm_vidc_debug_out;
extern int msm_fw_debug;
extern int msm_fw_debug_mode;
extern int msm_fw_low_power_mode;
@@ -49,11 +56,18 @@
#define dprintk(__level, __fmt, arg...) \
do { \
- if (msm_vidc_debug & __level) \
- printk(KERN_DEBUG VIDC_DBG_TAG \
- __fmt, __level, ## arg); \
+ if (msm_vidc_debug & __level) { \
+ if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
+ printk(KERN_DEBUG VIDC_DBG_TAG \
+ __fmt, __level, ## arg); \
+ } else if (msm_vidc_debug_out == VIDC_OUT_FTRACE) { \
+ trace_printk(KERN_DEBUG VIDC_DBG_TAG \
+ __fmt, __level, ## arg); \
+ } \
+ } \
} while (0)
+
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
struct dentry *parent);
struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index d9a2332..15f4e3f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -168,9 +168,9 @@
int samples;
};
-enum msm_vidc_mode {
- VIDC_NON_SECURE,
- VIDC_SECURE,
+enum msm_vidc_modes {
+ VIDC_SECURE = 1 << 0,
+ VIDC_TURBO = 1 << 1,
};
struct msm_vidc_core_capability {
@@ -225,7 +225,7 @@
void *priv;
struct msm_vidc_debug debug;
struct buf_count count;
- enum msm_vidc_mode mode;
+ enum msm_vidc_modes flags;
struct msm_vidc_core_capability capability;
};
@@ -254,4 +254,6 @@
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum hal_ssr_trigger_type type);
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+
#endif
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 577b2b5..0678fc2 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -618,6 +618,21 @@
HFI_CMD_SYS_SESSION_ABORT);
}
+static int q6_hfi_session_clean(void *session)
+{
+ struct hal_session *sess_close;
+ if (!session) {
+ dprintk(VIDC_ERR, "Invalid Params %s", __func__);
+ return -EINVAL;
+ }
+ sess_close = session;
+ dprintk(VIDC_DBG, "deleted the session: 0x%x",
+ sess_close->session_id);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ return 0;
+}
+
static int q6_hfi_session_set_buffers(void *sess,
struct vidc_buffer_addr_info *buffer_info)
{
@@ -1364,6 +1379,7 @@
hdev->session_init = q6_hfi_session_init;
hdev->session_end = q6_hfi_session_end;
hdev->session_abort = q6_hfi_session_abort;
+ hdev->session_clean = q6_hfi_session_clean;
hdev->session_set_buffers = q6_hfi_session_set_buffers;
hdev->session_release_buffers = q6_hfi_session_release_buffers;
hdev->session_load_res = q6_hfi_session_load_res;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index bc5adc11..8453b81 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -62,6 +62,23 @@
int ret;
};
+static void venus_hfi_dump_packet(u8 *packet)
+{
+ u32 c = 0, packet_size = *(u32 *)packet;
+ const int row_size = 32;
+ /* row must contain enough for 0xdeadbaad * 8 to be converted into
+ * "de ad ba ab " * 8 + '\0' */
+ char row[3 * row_size];
+
+ for (c = 0; c * row_size < packet_size; ++c) {
+ int bytes_to_read = ((c + 1) * row_size > packet_size) ?
+ packet_size % row_size : row_size;
+ hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
+ row_size, 4, row, sizeof(row), false);
+ dprintk(VIDC_PKT, "%s\n", row);
+ }
+}
+
static void venus_hfi_sim_modify_cmd_packet(u8 *packet)
{
struct hfi_cmd_sys_session_init_packet *sys_init;
@@ -171,8 +188,6 @@
return -EINVAL;
}
- venus_hfi_sim_modify_cmd_packet(packet);
-
queue = (struct hfi_queue_header *) qinfo->q_hdr;
if (!queue) {
@@ -180,6 +195,13 @@
return -ENOENT;
}
+ venus_hfi_sim_modify_cmd_packet(packet);
+
+ if (msm_vidc_debug & VIDC_PKT) {
+ dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+ venus_hfi_dump_packet(packet);
+ }
+
packet_size_in_words = (*(u32 *)packet) >> 2;
dprintk(VIDC_DBG, "Packet_size in words: %d", packet_size_in_words);
@@ -359,6 +381,10 @@
*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
venus_hfi_hal_sim_modify_msg_packet(packet);
+ if (msm_vidc_debug & VIDC_PKT) {
+ dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+ venus_hfi_dump_packet(packet);
+ }
dprintk(VIDC_DBG, "Out : ");
return rc;
}
@@ -1457,12 +1483,12 @@
goto err_session_init_fail;
}
- if (venus_hfi_iface_cmdq_write(dev, &pkt))
- goto err_session_init_fail;
if (venus_hfi_sys_set_debug(dev, msm_fw_debug))
dprintk(VIDC_ERR, "Setting fw_debug msg ON failed");
if (venus_hfi_sys_set_idle_message(dev, msm_fw_low_power_mode))
dprintk(VIDC_ERR, "Setting idle response ON failed");
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ goto err_session_init_fail;
return (void *) new_session;
err_session_init_fail:
@@ -1509,6 +1535,21 @@
HFI_CMD_SYS_SESSION_ABORT);
}
+static int venus_hfi_session_clean(void *session)
+{
+ struct hal_session *sess_close;
+ if (!session) {
+ dprintk(VIDC_ERR, "Invalid Params %s", __func__);
+ return -EINVAL;
+ }
+ sess_close = session;
+ dprintk(VIDC_DBG, "deleted the session: 0x%p",
+ sess_close);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ return 0;
+}
+
static int venus_hfi_session_set_buffers(void *sess,
struct vidc_buffer_addr_info *buffer_info)
{
@@ -2613,7 +2654,7 @@
static int venus_hfi_iommu_attach(struct venus_hfi_device *device)
{
- int rc;
+ int rc = 0;
struct iommu_domain *domain;
int i;
struct iommu_set *iommu_group_set;
@@ -2983,6 +3024,7 @@
hdev->session_init = venus_hfi_session_init;
hdev->session_end = venus_hfi_session_end;
hdev->session_abort = venus_hfi_session_abort;
+ hdev->session_clean = venus_hfi_session_clean;
hdev->session_set_buffers = venus_hfi_session_set_buffers;
hdev->session_release_buffers = venus_hfi_session_release_buffers;
hdev->session_load_res = venus_hfi_session_load_res;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 01395e5..389c13f 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -754,6 +754,10 @@
u32 nal_stream_format_supported;
};
+struct hal_nal_stream_format_select {
+ u32 nal_stream_format_select;
+};
+
struct hal_multi_view_format {
u32 views;
u32 rg_view_order[1];
@@ -1077,6 +1081,7 @@
int height, int *stride, int *scanlines);
int (*capability_check)(u32 fourcc, u32 width,
u32 *max_width, u32 *max_height);
+ int (*session_clean)(void *sess);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 6234dba..2b6d6bb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -476,6 +476,9 @@
u32 nal_stream_format_supported;
};
+struct hfi_nal_stream_format_select {
+ u32 nal_stream_format_select;
+};
#define HFI_PICTURE_TYPE_I 0x01
#define HFI_PICTURE_TYPE_P 0x02
#define HFI_PICTURE_TYPE_B 0x04
diff --git a/drivers/media/platform/msm/wfd/Kconfig b/drivers/media/platform/msm/wfd/Kconfig
index 6050d73..4fd668e 100644
--- a/drivers/media/platform/msm/wfd/Kconfig
+++ b/drivers/media/platform/msm/wfd/Kconfig
@@ -4,3 +4,9 @@
---help---
Enables the Wifi Display driver.
+menuconfig MSM_WFD_DEBUG
+ bool "Qualcomm MSM Wifi Display Driver Debug Mode"
+ depends on MSM_WFD
+ ---help---
+ Enables the Wifi Display driver in debug mode
+
diff --git a/drivers/media/platform/msm/wfd/Makefile b/drivers/media/platform/msm/wfd/Makefile
index 813bc64..c05f517 100644
--- a/drivers/media/platform/msm/wfd/Makefile
+++ b/drivers/media/platform/msm/wfd/Makefile
@@ -2,6 +2,8 @@
obj-y += wfd-ioctl.o
obj-y += wfd-util.o
obj-y += vsg-subdev.o
+
+ #pick up the MDP subdevice
ifeq ($(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL),y)
obj-y += mdp-4-subdev.o
else ifeq ($(CONFIG_FB_MSM_MDSS_WRITEBACK),y)
@@ -9,6 +11,14 @@
else
obj-y += mdp-dummy-subdev.o
endif
- obj-$(CONFIG_MSM_VIDC_1080P) += enc-mfc-subdev.o
- obj-$(CONFIG_MSM_VIDC_V4L2) += enc-venus-subdev.o
+
+ #pick up the Encoder subdevice
+ ifeq ($(CONFIG_MSM_VIDC_1080P),y)
+ obj-y += enc-mfc-subdev.o
+ else ifeq ($(CONFIG_MSM_VIDC_V4L2),y)
+ obj-y += enc-venus-subdev.o
+ else
+ obj-y += enc-dummy-subdev.o
+ endif
+
endif
diff --git a/drivers/media/platform/msm/wfd/enc-dummy-subdev.c b/drivers/media/platform/msm/wfd/enc-dummy-subdev.c
new file mode 100644
index 0000000..3acb6f8
--- /dev/null
+++ b/drivers/media/platform/msm/wfd/enc-dummy-subdev.c
@@ -0,0 +1,575 @@
+/* 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/list.h>
+#include <linux/mutex.h>
+#include <media/msm_media_info.h>
+#include <media/v4l2-subdev.h>
+#include "enc-subdev.h"
+#include "wfd-util.h"
+
+#ifndef CONFIG_MSM_WFD_DEBUG
+#error "Dummy subdevice must only be used when CONFIG_MSM_WFD_DEBUG=y"
+#endif
+
+#define DEFAULT_WIDTH 1920
+#define DEFAULT_HEIGHT 1080
+#define ALLOC_SIZE ALIGN((DEFAULT_WIDTH * DEFAULT_HEIGHT * 3) / 2, SZ_1M)
+#define FILL_SIZE ((DEFAULT_WIDTH * DEFAULT_HEIGHT * 3) / 2)
+
+static struct ion_client *venc_ion_client;
+struct venc_inst {
+ struct mutex lock;
+ struct venc_msg_ops vmops;
+ struct mem_region output_bufs, input_bufs;
+ struct workqueue_struct *wq;
+};
+
+struct encode_task {
+ struct venc_inst *inst;
+ struct work_struct work;
+};
+
+int venc_load_fw(struct v4l2_subdev *sd)
+{
+ return 0;
+}
+
+int venc_init(struct v4l2_subdev *sd, u32 val)
+{
+ if (!venc_ion_client)
+ venc_ion_client = msm_ion_client_create(-1, "wfd_enc_subdev");
+
+ return venc_ion_client ? 0 : -ENOMEM;
+}
+
+static long venc_open(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct venc_msg_ops *vmops = arg;
+ int rc = 0;
+
+ if (!vmops) {
+ WFD_MSG_ERR("Callbacks required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_open_fail;
+ } else if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_open_fail;
+ }
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst) {
+ WFD_MSG_ERR("Failed to allocate memory\n");
+ rc = -EINVAL;
+ goto venc_open_fail;
+ }
+
+ INIT_LIST_HEAD(&inst->output_bufs.list);
+ INIT_LIST_HEAD(&inst->input_bufs.list);
+ mutex_init(&inst->lock);
+ inst->wq = create_workqueue("venc-dummy-subdev");
+ inst->vmops = *vmops;
+ sd->dev_priv = inst;
+ vmops->cookie = inst;
+ return 0;
+venc_open_fail:
+ return rc;
+}
+
+static long venc_close(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_close_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ destroy_workqueue(inst->wq);
+ kfree(inst);
+ sd->dev_priv = inst = NULL;
+venc_close_fail:
+ return rc;
+
+}
+
+static long venc_get_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct bufreq *bufreq = arg;
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid buffer requirements\n");
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ }
+
+
+ bufreq->count = 3;
+ bufreq->size = ALLOC_SIZE;
+venc_buf_req_fail:
+ return rc;
+}
+
+static long venc_set_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct bufreq *bufreq = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid buffer requirements\n");
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ }
+
+ bufreq->size = ALLOC_SIZE;
+venc_buf_req_fail:
+ return rc;
+
+}
+
+static long venc_start(struct v4l2_subdev *sd)
+{
+ return 0;
+}
+
+static long venc_stop(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->wq);
+ return 0;
+}
+
+static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_set_format(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_format *fmt = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!fmt) {
+ WFD_MSG_ERR("Invalid format\n");
+ return -EINVAL;
+ } else if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ WFD_MSG_ERR("Invalid buffer type %d\n", fmt->type);
+ return -ENOTSUPP;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ fmt->fmt.pix.sizeimage = ALLOC_SIZE;
+ return 0;
+}
+
+static long venc_set_framerate(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static int venc_map_user_to_kernel(struct venc_inst *inst,
+ struct mem_region *mregion)
+{
+ int rc = 0;
+ unsigned long flags = 0;
+ if (!mregion) {
+ rc = -EINVAL;
+ goto venc_map_fail;
+ }
+
+ mregion->ion_handle = ion_import_dma_buf(venc_ion_client, mregion->fd);
+ if (IS_ERR_OR_NULL(mregion->ion_handle)) {
+ rc = PTR_ERR(mregion->ion_handle);
+ WFD_MSG_ERR("Failed to get handle: %p, %d, %d, %d\n",
+ venc_ion_client, mregion->fd, mregion->offset, rc);
+ mregion->ion_handle = NULL;
+ goto venc_map_fail;
+ }
+
+ rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ goto venc_map_fail;
+ }
+
+ mregion->paddr = mregion->kvaddr = ion_map_kernel(venc_ion_client,
+ mregion->ion_handle);
+
+ if (IS_ERR_OR_NULL(mregion->kvaddr)) {
+ WFD_MSG_ERR("Failed to map buffer into kernel\n");
+ rc = PTR_ERR(mregion->kvaddr);
+ mregion->kvaddr = NULL;
+ goto venc_map_fail;
+ }
+
+venc_map_fail:
+ return rc;
+}
+
+static int venc_unmap_user_to_kernel(struct venc_inst *inst,
+ struct mem_region *mregion)
+{
+ if (!mregion || !mregion->ion_handle)
+ return 0;
+
+ if (mregion->kvaddr) {
+ ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+ mregion->kvaddr = NULL;
+ }
+
+
+ return 0;
+}
+
+#ifdef CONFIG_MSM_VIDC_V4L2
+static int encode_memcpy(uint8_t *dst, uint8_t *src, int size)
+{
+ int y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, DEFAULT_WIDTH),
+ y_scan = VENUS_Y_SCANLINES(COLOR_FMT_NV12, DEFAULT_HEIGHT),
+ uv_stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, DEFAULT_WIDTH),
+ uv_scan = VENUS_UV_SCANLINES(COLOR_FMT_NV12, DEFAULT_HEIGHT);
+ int y_size = y_stride * y_scan;
+ int c = 0, dst_offset = 0, src_offset = 0;
+
+ /* copy the luma */
+ for (c = 0; c < DEFAULT_HEIGHT; ++c) {
+ memcpy(dst + dst_offset, src + src_offset, DEFAULT_WIDTH);
+ src_offset += y_stride;
+ dst_offset += DEFAULT_WIDTH;
+ }
+
+ /* skip over padding between luma and chroma */
+ src_offset = y_size;
+ /* now do the chroma */
+ for (c = 0; c < DEFAULT_HEIGHT / 2; ++c) {
+ memcpy(dst + dst_offset, src + src_offset, DEFAULT_WIDTH);
+ src_offset += uv_stride;
+ dst_offset += DEFAULT_WIDTH;
+ }
+
+ (void)uv_scan;
+ return dst_offset;
+}
+#else
+static int encode_memcpy(uint8_t *dst, uint8_t *src, int size)
+{
+ memcpy(dst, src, size);
+ return size;
+}
+#endif
+
+static void encode(struct work_struct *work)
+{
+ struct encode_task *et = NULL;
+ struct venc_inst *inst = NULL;
+ struct mem_region *input, *output;
+ struct vb2_buffer *vb;
+ int bytes_copied = 0;
+ if (!work)
+ return;
+
+ et = container_of(work, struct encode_task, work);
+ inst = et->inst;
+
+ mutex_lock(&inst->lock);
+ if (list_empty(&inst->input_bufs.list)) {
+ WFD_MSG_ERR("Can't find an input buffer");
+ mutex_unlock(&inst->lock);
+ return;
+ }
+
+ if (list_empty(&inst->output_bufs.list)) {
+ WFD_MSG_ERR("Can't find an output buffer");
+ mutex_unlock(&inst->lock);
+ return;
+ }
+
+ /* Grab an i/p & o/p buffer pair */
+ input = list_first_entry(&inst->input_bufs.list,
+ struct mem_region, list);
+ list_del(&input->list);
+
+ output = list_first_entry(&inst->output_bufs.list,
+ struct mem_region, list);
+ list_del(&output->list);
+ mutex_unlock(&inst->lock);
+
+ /* This is our "encode" */
+ bytes_copied = encode_memcpy(output->kvaddr, input->kvaddr,
+ min(output->size, input->size));
+
+ vb = (struct vb2_buffer *)output->cookie;
+ vb->v4l2_planes[0].bytesused = bytes_copied;
+ inst->vmops.op_buffer_done(
+ inst->vmops.cbdata, 0, vb);
+
+ inst->vmops.ip_buffer_done(
+ inst->vmops.cbdata,
+ 0, input);
+
+ venc_unmap_user_to_kernel(inst, output);
+ kfree(input);
+ kfree(output);
+ kfree(et);
+}
+
+static void prepare_for_encode(struct venc_inst *inst)
+{
+ struct encode_task *et = kzalloc(sizeof(*et), GFP_KERNEL);
+ et->inst = inst;
+ INIT_WORK(&et->work, encode);
+ queue_work(inst->wq, &et->work);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct mem_region *mregion = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer in %s", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ /* check for dupes */
+ list_for_each_entry(mregion, &inst->output_bufs.list, list) {
+ struct mem_region *temp = arg;
+ if (mem_region_equals(temp, mregion)) {
+ WFD_MSG_ERR("Attempt to queue dupe buffer\n");
+ return -EEXIST;
+ }
+ }
+
+ mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+ if (!mregion) {
+ WFD_MSG_ERR("Invalid output buffer in %s", __func__);
+ return -EINVAL;
+ }
+
+ *mregion = *(struct mem_region *)arg;
+
+ if (venc_map_user_to_kernel(inst, mregion)) {
+ WFD_MSG_ERR("unable to map buffer into kernel\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&inst->lock);
+ list_add_tail(&mregion->list, &inst->output_bufs.list);
+
+ if (!list_empty(&inst->input_bufs.list))
+ prepare_for_encode(inst);
+ mutex_unlock(&inst->lock);
+
+ return 0;
+}
+
+static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct venc_buf_info *venc_buf = arg;
+ struct mem_region *mregion = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!venc_buf) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+ if (!mregion) {
+ WFD_MSG_ERR("Invalid output buffer in %s", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ *mregion = *venc_buf->mregion;
+
+ mutex_lock(&inst->lock);
+ list_add_tail(&mregion->list, &inst->input_bufs.list);
+
+ if (!list_empty(&inst->output_bufs.list))
+ prepare_for_encode(inst);
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
+static long venc_alloc_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_free_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_flush_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_set_property(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_get_property(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+
+ mregion = mmap->mregion;
+ mregion->paddr = mregion->kvaddr;
+ return 0;
+}
+
+static long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+ void *arg)
+{
+ return 0;
+}
+
+long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ long rc = 0;
+ switch (cmd) {
+ case OPEN:
+ rc = venc_open(sd, arg);
+ break;
+ case CLOSE:
+ rc = venc_close(sd, arg);
+ break;
+ case ENCODE_START:
+ rc = venc_start(sd);
+ break;
+ case ENCODE_FRAME:
+ venc_encode_frame(sd, arg);
+ break;
+ case ENCODE_STOP:
+ rc = venc_stop(sd);
+ break;
+ case SET_PROP:
+ rc = venc_set_property(sd, arg);
+ break;
+ case GET_PROP:
+ rc = venc_get_property(sd, arg);
+ break;
+ case GET_BUFFER_REQ:
+ rc = venc_get_buffer_req(sd, arg);
+ break;
+ case SET_BUFFER_REQ:
+ rc = venc_set_buffer_req(sd, arg);
+ break;
+ case FREE_BUFFER:
+ break;
+ case FILL_OUTPUT_BUFFER:
+ rc = venc_fill_outbuf(sd, arg);
+ break;
+ case SET_FORMAT:
+ rc = venc_set_format(sd, arg);
+ break;
+ case SET_FRAMERATE:
+ rc = venc_set_framerate(sd, arg);
+ break;
+ case SET_INPUT_BUFFER:
+ rc = venc_set_input_buffer(sd, arg);
+ break;
+ case SET_OUTPUT_BUFFER:
+ rc = venc_set_output_buffer(sd, arg);
+ break;
+ case ALLOC_RECON_BUFFERS:
+ rc = venc_alloc_recon_buffers(sd, arg);
+ break;
+ case FREE_OUTPUT_BUFFER:
+ rc = venc_free_output_buffer(sd, arg);
+ break;
+ case FREE_INPUT_BUFFER:
+ rc = venc_free_input_buffer(sd, arg);
+ break;
+ case FREE_RECON_BUFFERS:
+ rc = venc_free_recon_buffers(sd, arg);
+ break;
+ case ENCODE_FLUSH:
+ rc = venc_flush_buffers(sd, arg);
+ break;
+ case ENC_MMAP:
+ rc = venc_mmap(sd, arg);
+ break;
+ case ENC_MUNMAP:
+ rc = venc_munmap(sd, arg);
+ break;
+ case SET_FRAMERATE_MODE:
+ rc = venc_set_framerate_mode(sd, arg);
+ break;
+ default:
+ WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 722aa8f..8121471 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include <media/v4l2-subdev.h>
@@ -48,6 +49,13 @@
bool callback_thread_running;
struct completion dq_complete, cmd_complete;
bool secure;
+ struct workqueue_struct *fill_buf_wq;
+};
+
+struct fill_buf_work {
+ struct venc_inst *inst;
+ struct mem_region *mregion;
+ struct work_struct work;
};
static const int subscribed_events[] = {
@@ -70,6 +78,26 @@
return venc_ion_client ? 0 : -ENOMEM;
}
+static int invalidate_cache(struct ion_client *client,
+ struct mem_region *mregion)
+{
+ if (!client || !mregion) {
+ WFD_MSG_ERR(
+ "Failed to flush ion buffer: invalid client or region\n");
+ return -EINVAL;
+ } else if (!mregion->ion_handle) {
+ WFD_MSG_ERR(
+ "Failed to flush ion buffer: not an ion buffer\n");
+ return -EINVAL;
+ }
+
+ return msm_ion_do_cache_op(client,
+ mregion->ion_handle,
+ mregion->kvaddr,
+ mregion->size,
+ ION_IOC_INV_CACHES);
+
+}
static int next_free_index(struct index_bitmap *index_bitmap)
{
int index = find_first_zero_bit(index_bitmap->bitmap,
@@ -229,6 +257,16 @@
vb->v4l2_planes[0].bytesused =
buffer.m.planes[0].bytesused;
+ /* Buffer is on its way to userspace, so
+ * invalidate the cache */
+ rc = invalidate_cache(venc_ion_client, mregion);
+ if (rc) {
+ WFD_MSG_WARN(
+ "Failed to invalidate cache %d\n",
+ rc);
+ /* Not fatal, move on */
+ }
+
inst->vmops.op_buffer_done(
inst->vmops.cbdata, 0, vb);
} else if (buffer.type == BUF_TYPE_INPUT &&
@@ -258,13 +296,24 @@
static long set_default_properties(struct venc_inst *inst)
{
struct v4l2_control ctrl = {0};
+ int rc;
/* Set the IDR period as 1. The venus core doesn't give
* the sps/pps for I-frames, only IDR. */
ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD;
ctrl.value = 1;
+ rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+ if (rc)
+ WFD_MSG_WARN("Failed to set IDR period\n");
- return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+ /* Set the default rc mode to VBR/VFR, client can change later */
+ ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
+ ctrl.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
+ rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+ if (rc)
+ WFD_MSG_WARN("Failed to set rc mode\n");
+
+ return 0;
}
static int subscribe_events(struct venc_inst *inst)
@@ -331,6 +380,14 @@
init_completion(&inst->dq_complete);
init_completion(&inst->cmd_complete);
mutex_init(&inst->lock);
+
+ inst->fill_buf_wq = create_singlethread_workqueue("venc_vidc_ftb_wq");
+ if (!inst->fill_buf_wq) {
+ WFD_MSG_ERR("Failed to create ftb wq\n");
+ rc = -ENOMEM;
+ goto vidc_wq_create_fail;
+ }
+
inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
if (!inst->vidc_context) {
WFD_MSG_ERR("Failed to create vidc context\n");
@@ -362,6 +419,8 @@
vidc_subscribe_fail:
msm_vidc_close(inst->vidc_context);
vidc_open_fail:
+ destroy_workqueue(inst->fill_buf_wq);
+vidc_wq_create_fail:
kfree(inst);
venc_open_fail:
return rc;
@@ -385,6 +444,7 @@
wait_for_completion(&inst->cmd_complete);
+ destroy_workqueue(inst->fill_buf_wq);
if (inst->callback_thread && inst->callback_thread_running)
kthread_stop(inst->callback_thread);
@@ -551,6 +611,7 @@
inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->fill_buf_wq);
rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
if (rc) {
WFD_MSG_ERR("Failed to streamoff vidc's input port");
@@ -646,6 +707,33 @@
return rc;
}
+#ifdef CONFIG_MSM_WFD_DEBUG
+static void *venc_map_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return ion_map_kernel(client, handle);
+}
+
+static void venc_unmap_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ ion_unmap_kernel(client, handle);
+}
+#else
+
+static void *venc_map_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return NULL;
+}
+
+static void venc_unmap_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return;
+}
+#endif
+
static int venc_map_user_to_kernel(struct venc_inst *inst,
struct mem_region *mregion)
{
@@ -680,18 +768,8 @@
goto venc_map_fail;
}
- if (!inst->secure) {
- mregion->kvaddr = ion_map_kernel(venc_ion_client,
- mregion->ion_handle);
- if (IS_ERR_OR_NULL(mregion->kvaddr)) {
- WFD_MSG_ERR("Failed to map buffer into kernel\n");
- rc = PTR_ERR(mregion->kvaddr);
- mregion->kvaddr = NULL;
- goto venc_map_fail;
- }
- } else {
- mregion->kvaddr = NULL;
- }
+ mregion->kvaddr = inst->secure ? NULL :
+ venc_map_kernel(venc_ion_client, mregion->ion_handle);
if (inst->secure) {
rc = msm_ion_secure_buffer(venc_ion_client,
@@ -728,8 +806,8 @@
if (inst->secure)
msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
venc_map_iommu_map_fail:
- if (!inst->secure)
- ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+ if (!inst->secure && !IS_ERR_OR_NULL(mregion->kvaddr))
+ venc_unmap_kernel(venc_ion_client, mregion->ion_handle);
venc_map_fail:
return rc;
}
@@ -762,8 +840,8 @@
mregion->paddr = NULL;
}
- if (mregion->kvaddr) {
- ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+ if (!IS_ERR_OR_NULL(mregion->kvaddr)) {
+ venc_unmap_kernel(venc_ion_client, mregion->ion_handle);
mregion->kvaddr = NULL;
}
@@ -938,25 +1016,12 @@
return msm_vidc_s_parm(inst->vidc_context, &p);
}
-static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+static long fill_outbuf(struct venc_inst *inst, struct mem_region *mregion)
{
- struct venc_inst *inst = NULL;
- struct mem_region *mregion = NULL;
struct v4l2_buffer buffer = {0};
struct v4l2_plane plane = {0};
int index = 0, rc = 0;
- if (!sd) {
- WFD_MSG_ERR("Subdevice required for %s\n", __func__);
- return -EINVAL;
- } else if (!arg) {
- WFD_MSG_ERR("Invalid output buffer ot fill\n");
- return -EINVAL;
- }
-
- inst = (struct venc_inst *)sd->dev_priv;
- mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
-
if (!mregion) {
WFD_MSG_ERR("Output buffer not registered\n");
return -ENOENT;
@@ -994,8 +1059,77 @@
mark_index_busy(&inst->free_output_indices, index);
mutex_unlock(&inst->lock);
}
- return rc;
+ return rc;
+}
+
+static void fill_outbuf_helper(struct work_struct *work)
+{
+ int rc;
+ struct fill_buf_work *fbw =
+ container_of(work, struct fill_buf_work, work);
+
+ rc = fill_outbuf(fbw->inst, fbw->mregion);
+ if (rc) {
+ struct vb2_buffer *vb = NULL;
+
+ WFD_MSG_ERR("Failed to fill buffer async\n");
+ vb = (struct vb2_buffer *)fbw->mregion->cookie;
+ vb->v4l2_buf.flags = 0;
+ vb->v4l2_buf.timestamp = ns_to_timeval(-1);
+ vb->v4l2_planes[0].bytesused = 0;
+
+ fbw->inst->vmops.op_buffer_done(
+ fbw->inst->vmops.cbdata, rc, vb);
+ }
+
+ kfree(fbw);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ struct fill_buf_work *fbw;
+ struct venc_inst *inst = NULL;
+ struct mem_region *mregion;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+ if (!mregion) {
+ WFD_MSG_ERR("Output buffer not registered\n");
+ return -ENOENT;
+ }
+
+ fbw = kzalloc(sizeof(*fbw), GFP_KERNEL);
+ if (!fbw) {
+ WFD_MSG_ERR("Couldn't allocate memory\n");
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&fbw->work, fill_outbuf_helper);
+ fbw->inst = inst;
+ fbw->mregion = mregion;
+ /* XXX: The need for a wq to qbuf to vidc is necessitated as a
+ * workaround for a bug in the v4l2 framework. VIDIOC_QBUF from
+ * triggers a down_read(current->mm->mmap_sem). There is another
+ * _read(..) as msm_vidc_qbuf() depends on videobuf2 framework
+ * as well. However, a _write(..) after the first _read() by a
+ * different driver will prevent the second _read(...) from
+ * suceeding.
+ *
+ * As we can't modify the framework, we're working around by issue
+ * by queuing in a different thread effectively.
+ */
+ queue_work(inst->fill_buf_wq, &fbw->work);
+
+ return 0;
}
static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
@@ -1127,6 +1261,8 @@
inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->fill_buf_wq);
+
enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
enc_cmd.flags = V4L2_QCOM_CMD_FLUSH_OUTPUT |
V4L2_QCOM_CMD_FLUSH_CAPTURE;
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 6399117..97204ae 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -73,7 +73,7 @@
mops->cookie = inst;
return 0;
mdp_secure_fail:
- msm_fb_writeback_terminate(inst->mdp);
+ msm_fb_writeback_terminate(fbi);
mdp_open_fail:
kfree(inst);
return rc;
@@ -83,19 +83,12 @@
{
struct mdp_instance *inst = arg;
int rc = 0;
- struct fb_info *fbi = NULL;
if (inst) {
rc = msm_fb_writeback_start(inst->mdp);
if (rc) {
WFD_MSG_ERR("Failed to start MDP mode\n");
goto exit;
}
- fbi = msm_fb_get_writeback_fb();
- if (!fbi) {
- WFD_MSG_ERR("Failed to acquire mdp instance\n");
- rc = -ENODEV;
- goto exit;
- }
}
exit:
return rc;
@@ -105,7 +98,6 @@
{
struct mdp_instance *inst = arg;
int rc = 0;
- struct fb_info *fbi = NULL;
if (inst) {
rc = msm_fb_writeback_stop(inst->mdp);
if (rc) {
@@ -113,7 +105,6 @@
return rc;
}
- fbi = (struct fb_info *)inst->mdp;
}
return 0;
}
@@ -121,12 +112,10 @@
static int mdp_close(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = arg;
- struct fb_info *fbi = NULL;
if (inst) {
- fbi = (struct fb_info *)inst->mdp;
if (inst->secure)
msm_fb_writeback_set_secure(inst->mdp, false);
- msm_fb_writeback_terminate(fbi);
+ msm_fb_writeback_terminate(inst->mdp);
kfree(inst);
}
return 0;
diff --git a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
index 10ba3c3..46977a6 100644
--- a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
@@ -19,6 +19,10 @@
#include "mdp-subdev.h"
#include "wfd-util.h"
+#ifndef CONFIG_MSM_WFD_DEBUG
+#error "Dummy subdevice must only be used when CONFIG_MSM_WFD_DEBUG=y"
+#endif
+
struct mdp_buf_queue {
struct mdp_buf_info mdp_buf_info;
struct list_head node;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index d44792c..30a666d 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -158,11 +158,36 @@
return (unsigned long)NULL;
}
+#ifdef CONFIG_MSM_WFD_DEBUG
+static void *wfd_map_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return ion_map_kernel(client, handle);
+}
+
+static void wfd_unmap_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ ion_unmap_kernel(client, handle);
+}
+#else
+static void *wfd_map_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return NULL;
+}
+
+static void wfd_unmap_kernel(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return;
+}
+#endif
+
static int wfd_allocate_ion_buffer(struct ion_client *client,
bool secure, struct mem_region *mregion)
{
struct ion_handle *handle = NULL;
- void *kvaddr = NULL;
unsigned int alloc_regions = 0, ion_flags = 0, align = 0;
int rc = 0;
@@ -184,26 +209,14 @@
goto alloc_fail;
}
- if (!secure) {
- kvaddr = ion_map_kernel(client, handle);
-
- if (IS_ERR_OR_NULL(kvaddr)) {
- WFD_MSG_ERR("Failed to get virtual addr\n");
- rc = PTR_ERR(kvaddr);
- goto alloc_fail;
- }
- } else {
- kvaddr = NULL;
- }
-
- mregion->kvaddr = kvaddr;
+ mregion->kvaddr = secure ? NULL :
+ wfd_map_kernel(client, handle);
mregion->ion_handle = handle;
-
return rc;
alloc_fail:
if (!IS_ERR_OR_NULL(handle)) {
- if (!IS_ERR_OR_NULL(kvaddr))
- ion_unmap_kernel(client, handle);
+ if (!IS_ERR_OR_NULL(mregion->kvaddr))
+ wfd_unmap_kernel(client, handle);
ion_free(client, handle);
@@ -223,8 +236,10 @@
"Invalid client or region");
return -EINVAL;
}
- if (mregion->kvaddr)
- ion_unmap_kernel(client, mregion->ion_handle);
+
+ if (!IS_ERR_OR_NULL(mregion->kvaddr))
+ wfd_unmap_kernel(client, mregion->ion_handle);
+
ion_free(client, mregion->ion_handle);
return 0;
}
@@ -1258,7 +1273,7 @@
WFD_MSG_DBG("yay!! got callback\n");
mutex_lock(&inst->vb2_lock);
- vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+ vb2_buffer_done(buf, status ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
mutex_unlock(&inst->vb2_lock);
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 130ff48..3d0abce 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -283,14 +283,6 @@
},
};
-
-enum wcd9xxx_chipid_major {
- TABLA_MAJOR = cpu_to_le16(0x100),
- SITAR_MAJOR = cpu_to_le16(0x101),
- TAIKO_MAJOR = cpu_to_le16(0x102),
- TAPAN_MAJOR = cpu_to_le16(0x103),
-};
-
static const struct wcd9xxx_codec_type wcd9xxx_codecs[] = {
{
TABLA_MAJOR, cpu_to_le16(0x1), tabla1x_devs,
@@ -1729,6 +1721,7 @@
.id_table = tapan_slimtest_id,
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
+ .device_up = wcd9xxx_slim_device_up,
};
static struct i2c_device_id wcd9xxx_id_table[] = {
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 5efd905..062351d 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -193,10 +193,24 @@
mutex_unlock(&wcd9xxx->nested_irq_lock);
}
-static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
+static bool wcd9xxx_is_mbhc_irq(struct wcd9xxx *wcd9xxx, int irqbit)
{
if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
- (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL)) {
+ (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL))
+ return true;
+ else if (wcd9xxx->codec_type->id_major == TAIKO_MAJOR &&
+ irqbit == WCD9320_IRQ_MBHC_JACK_SWITCH)
+ return true;
+ else if (wcd9xxx->codec_type->id_major == TAPAN_MAJOR &&
+ irqbit == WCD9306_IRQ_MBHC_JACK_SWITCH)
+ return true;
+ else
+ return false;
+}
+
+static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
+{
+ if (wcd9xxx_is_mbhc_irq(wcd9xxx, irqbit)) {
wcd9xxx_nested_irq_lock(wcd9xxx);
wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
BIT_BYTE(irqbit),
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 07eb472..c60537a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -998,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;
@@ -1057,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;
@@ -1065,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);
}
@@ -1101,15 +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;
-
ret = __qseecom_send_cmd(data, &send_cmd_req);
- __qseecom_send_cmd_req_clean_up(&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;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index e0fffbd..a395b7c 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -46,6 +46,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/string.h>
+#include <mach/msm_bus.h>
/*
* General defines
@@ -437,6 +438,7 @@
struct list_head devlist; /* list of all devices */
struct platform_device *pdev;
void __iomem *base;
+ uint32_t tsif_bus_client;
unsigned int tspp_irq;
unsigned int bam_irq;
u32 bam_handle;
@@ -773,12 +775,24 @@
return -EINVAL;
}
+ if (device->tsif_bus_client) {
+ rc = msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 1);
+ if (rc) {
+ pr_err("tspp: Can't enable bus\n");
+ return -EBUSY;
+ }
+ }
+
if (device->tsif_vreg) {
rc = regulator_set_voltage(device->tsif_vreg,
RPM_REGULATOR_CORNER_SUPER_TURBO,
RPM_REGULATOR_CORNER_SUPER_TURBO);
if (rc) {
pr_err("Unable to set CX voltage.\n");
+ if (device->tsif_bus_client)
+ msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
return rc;
}
}
@@ -791,6 +805,10 @@
RPM_REGULATOR_CORNER_SVS_SOC,
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
+
+ if (device->tsif_bus_client)
+ msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
return -EBUSY;
}
@@ -803,6 +821,10 @@
RPM_REGULATOR_CORNER_SVS_SOC,
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
+
+ if (device->tsif_bus_client)
+ msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
return -EBUSY;
}
@@ -831,6 +853,13 @@
if (rc)
pr_err("Unable to set CX voltage.\n");
}
+
+ if (device->tsif_bus_client) {
+ rc = msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
+ if (rc)
+ pr_err("tspp: Can't disable bus\n");
+ }
}
/*** TSIF functions ***/
@@ -2851,6 +2880,7 @@
struct resource *mem_tspp;
struct resource *mem_bam;
struct tspp_channel *channel;
+ struct msm_bus_scale_pdata *tspp_bus_pdata = NULL;
if (pdev->dev.of_node) {
/* get information from device tree */
@@ -2862,9 +2892,12 @@
pdev->id = -1;
pdev->dev.platform_data = data;
+
+ tspp_bus_pdata = msm_bus_cl_get_pdata(pdev);
} else {
/* must have platform data */
data = pdev->dev.platform_data;
+ tspp_bus_pdata = NULL;
}
if (!data) {
pr_err("tspp: Platform data not available");
@@ -2891,6 +2924,16 @@
device->pdev = pdev;
platform_set_drvdata(pdev, device);
+ /* register bus client */
+ if (tspp_bus_pdata) {
+ device->tsif_bus_client =
+ msm_bus_scale_register_client(tspp_bus_pdata);
+ if (!device->tsif_bus_client)
+ pr_err("tspp: Unable to register bus client\n");
+ } else {
+ device->tsif_bus_client = 0;
+ }
+
/* map regulators */
if (data->tsif_vreg_present) {
device->tsif_vreg = devm_regulator_get(&pdev->dev, "vdd_cx");
@@ -3108,6 +3151,8 @@
if (device->tsif_vreg)
regulator_disable(device->tsif_vreg);
err_regultaor:
+ if (device->tsif_bus_client)
+ msm_bus_scale_unregister_client(device->tsif_bus_client);
kfree(device);
out:
@@ -3143,6 +3188,9 @@
free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
}
+ if (device->tsif_bus_client)
+ msm_bus_scale_unregister_client(device->tsif_bus_client);
+
wake_lock_destroy(&device->wake_lock);
free_irq(device->tspp_irq, device);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 21e65b9..f01ddab 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3122,6 +3122,37 @@
#endif
}
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+ struct mmc_blk_data *part_md;
+ struct mmc_blk_data *md = mmc_get_drvdata(card);
+ int rc;
+
+ /* Silent the block layer */
+ if (md) {
+ rc = mmc_queue_suspend(&md->queue);
+ if (rc)
+ goto suspend_error;
+ list_for_each_entry(part_md, &md->part, part) {
+ rc = mmc_queue_suspend(&part_md->queue);
+ if (rc)
+ goto suspend_error;
+ }
+ }
+
+ /* send power off notification */
+ if (mmc_card_mmc(card)) {
+ mmc_rpm_hold(card->host, &card->dev);
+ mmc_send_long_pon(card);
+ mmc_rpm_release(card->host, &card->dev);
+ }
+ return;
+
+suspend_error:
+ pr_err("%s: mmc_queue_suspend returned error = %d",
+ mmc_hostname(card->host), rc);
+}
+
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
{
@@ -3181,6 +3212,7 @@
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
+ .shutdown = mmc_blk_shutdown,
};
static int __init mmc_blk_init(void)
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 7b9e133..ac2ecbb 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -123,6 +123,15 @@
return 0;
}
+static void mmc_bus_shutdown(struct device *dev)
+{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ if (drv->shutdown)
+ drv->shutdown(card);
+}
+
#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
@@ -153,10 +162,18 @@
{
struct mmc_card *card = mmc_dev_to_card(dev);
- if (mmc_use_core_runtime_pm(card->host))
- return 0;
- else
+ if (mmc_use_core_runtime_pm(card->host)) {
+ /*
+ * If idle time bkops is running on the card, let's not get
+ * into suspend.
+ */
+ if (mmc_card_doing_bkops(card) && mmc_card_is_prog_state(card))
+ return -EBUSY;
+ else
+ return 0;
+ } else {
return mmc_power_save_host(card->host);
+ }
}
static int mmc_runtime_resume(struct device *dev)
@@ -238,6 +255,7 @@
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
+ .shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
index 2c14be7..14dd313 100644
--- a/drivers/mmc/core/cd-gpio.c
+++ b/drivers/mmc/core/cd-gpio.c
@@ -20,12 +20,44 @@
struct mmc_cd_gpio {
unsigned int gpio;
char label[0];
+ bool status;
};
+static int mmc_cd_get_status(struct mmc_host *host)
+{
+ int ret = -ENOSYS;
+ struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
+
+ if (!cd || !gpio_is_valid(cd->gpio))
+ goto out;
+
+ ret = !gpio_get_value_cansleep(cd->gpio) ^
+ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+out:
+ return ret;
+}
+
static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
{
- /* Schedule a card detection after a debounce timeout */
- mmc_detect_change(dev_id, msecs_to_jiffies(100));
+ struct mmc_host *host = dev_id;
+ struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
+ int status;
+
+ status = mmc_cd_get_status(host);
+ if (unlikely(status < 0))
+ goto out;
+
+ if (status ^ cd->status) {
+ pr_info("%s: slot status change detected (%d -> %d), GPIO_ACTIVE_%s\n",
+ mmc_hostname(host), cd->status, status,
+ (host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) ?
+ "HIGH" : "LOW");
+ cd->status = status;
+
+ /* Schedule a card detection after a debounce timeout */
+ mmc_detect_change(host, msecs_to_jiffies(100));
+ }
+out:
return IRQ_HANDLED;
}
@@ -49,16 +81,22 @@
if (ret < 0)
goto egpioreq;
+ cd->gpio = gpio;
+ host->hotplug.irq = irq;
+ host->hotplug.handler_priv = cd;
+
+ ret = mmc_cd_get_status(host);
+ if (ret < 0)
+ goto eirqreq;
+
+ cd->status = ret;
+
ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
cd->label, host);
if (ret < 0)
goto eirqreq;
- cd->gpio = gpio;
- host->hotplug.irq = irq;
- host->hotplug.handler_priv = cd;
-
return 0;
eirqreq:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9fc599b..04687fa 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -487,11 +487,6 @@
mmc_card_clr_need_bkops(card);
mmc_card_set_doing_bkops(card);
- pr_debug("%s: %s: starting the polling thread\n",
- mmc_hostname(card->host), __func__);
- queue_work(system_nrt_wq,
- &card->bkops_info.poll_for_completion);
-
out:
mmc_release_host(card->host);
mmc_rpm_release(card->host, &card->dev);
@@ -499,81 +494,6 @@
EXPORT_SYMBOL(mmc_start_bkops);
/**
- * mmc_bkops_completion_polling() - Poll on the card status to
- * wait for the non-blocking BKOPS completion
- * @work: The completion polling work
- *
- * The on-going reading of the card status will prevent the card
- * from getting into suspend while it is in the middle of
- * performing BKOPS.
- * Since the non blocking BKOPS can be interrupted by a fetched
- * request we also check IF mmc_card_doing_bkops in each
- * iteration.
- */
-void mmc_bkops_completion_polling(struct work_struct *work)
-{
- struct mmc_card *card = container_of(work, struct mmc_card,
- bkops_info.poll_for_completion);
- unsigned long timeout_jiffies = jiffies +
- msecs_to_jiffies(BKOPS_COMPLETION_POLLING_TIMEOUT_MS);
- u32 status;
- int err;
-
- /*
- * Wait for the BKOPs to complete. Keep reading the status to prevent
- * the host from getting into suspend
- */
- do {
- mmc_rpm_hold(card->host, &card->dev);
- mmc_claim_host(card->host);
-
- if (!mmc_card_doing_bkops(card))
- goto out;
-
- err = mmc_send_status(card, &status);
- if (err) {
- pr_err("%s: error %d requesting status\n",
- mmc_hostname(card->host), err);
- goto out;
- }
-
- /*
- * Some cards mishandle the status bits, so make sure to check
- * both the busy indication and the card state.
- */
- if ((status & R1_READY_FOR_DATA) &&
- (R1_CURRENT_STATE(status) != R1_STATE_PRG)) {
- pr_debug("%s: %s: completed BKOPs, exit polling\n",
- mmc_hostname(card->host), __func__);
- mmc_card_clr_doing_bkops(card);
- card->bkops_info.sectors_changed = 0;
- goto out;
- }
-
- mmc_release_host(card->host);
- mmc_rpm_release(card->host, &card->dev);
-
- /*
- * Sleep before checking the card status again to allow the
- * card to complete the BKOPs operation
- */
- msleep(BKOPS_COMPLETION_POLLING_INTERVAL_MS);
- } while (time_before(jiffies, timeout_jiffies));
-
- pr_err("%s: %s: exit polling due to timeout, stop bkops\n",
- mmc_hostname(card->host), __func__);
- err = mmc_stop_bkops(card);
- if (err)
- pr_err("%s: %s: mmc_stop_bkops failed, err=%d\n",
- mmc_hostname(card->host), __func__, err);
-
- return;
-out:
- mmc_release_host(card->host);
- mmc_rpm_release(card->host, &card->dev);
-}
-
-/**
* mmc_start_idle_time_bkops() - check if a non urgent BKOPS is
* needed
* @work: The idle time BKOPS work
@@ -1066,6 +986,36 @@
}
EXPORT_SYMBOL(mmc_wait_for_req);
+bool mmc_card_is_prog_state(struct mmc_card *card)
+{
+ bool rc;
+ struct mmc_command cmd;
+
+ mmc_claim_host(card->host);
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = MMC_SEND_STATUS;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ rc = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (rc) {
+ pr_err("%s: Get card status fail. rc=%d\n",
+ mmc_hostname(card->host), rc);
+ rc = false;
+ goto out;
+ }
+
+ if (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)
+ rc = true;
+ else
+ rc = false;
+out:
+ mmc_release_host(card->host);
+ return rc;
+}
+EXPORT_SYMBOL(mmc_card_is_prog_state);
+
/**
* mmc_interrupt_hpi - Issue for High priority Interrupt
* @card: the MMC card associated with the HPI transfer
@@ -1123,8 +1073,13 @@
if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
break;
- if (time_after(jiffies, prg_wait))
- err = -ETIMEDOUT;
+ if (time_after(jiffies, prg_wait)) {
+ err = mmc_send_status(card, &status);
+ if (!err && R1_CURRENT_STATE(status) != R1_STATE_TRAN)
+ err = -ETIMEDOUT;
+ else
+ break;
+ }
} while (!err);
out:
@@ -1189,6 +1144,17 @@
if (!mmc_card_doing_bkops(card))
goto out;
+ /*
+ * If idle time bkops is running on the card, let's not get into
+ * suspend.
+ */
+ if (!mmc_use_core_runtime_pm(card->host) && mmc_card_doing_bkops(card)
+ && (card->host->parent->power.runtime_status == RPM_SUSPENDING)
+ && mmc_card_is_prog_state(card)) {
+ err = -EBUSY;
+ goto out;
+ }
+
err = mmc_interrupt_hpi(card);
/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6c03bfc..edd6a5d 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -253,11 +253,19 @@
* mmc_host_may_gate_card - check if this card may be gated
* @card: card to check.
*/
-static bool mmc_host_may_gate_card(struct mmc_card *card)
+bool mmc_host_may_gate_card(struct mmc_card *card)
{
/* If there is no card we may gate it */
if (!card)
return true;
+
+ /*
+ * SDIO3.0 card allows the clock to be gated off so check if
+ * that is the case or not.
+ */
+ if (mmc_card_sdio(card) && card->cccr.async_intr_sup)
+ return true;
+
/*
* Don't gate SDIO cards! These need to be clocked at all times
* since they may be independent systems generating interrupts
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 89f8c91..9b9c1ed 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -18,6 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
#include "core.h"
#include "bus.h"
@@ -900,6 +901,20 @@
return err;
}
+static int mmc_reboot_notify(struct notifier_block *notify_block,
+ unsigned long event, void *unused)
+{
+ struct mmc_card *card = container_of(
+ notify_block, struct mmc_card, reboot_notify);
+
+ if (event != SYS_RESTART)
+ card->issue_long_pon = true;
+ else
+ card->issue_long_pon = false;
+
+ return NOTIFY_OK;
+}
+
/*
* Handle the detection and initialisation of a card.
*
@@ -979,6 +994,7 @@
card->type = MMC_TYPE_MMC;
card->rca = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ card->reboot_notify.notifier_call = mmc_reboot_notify;
}
/*
@@ -1400,8 +1416,6 @@
if (card->ext_csd.bkops_en) {
INIT_DELAYED_WORK(&card->bkops_info.dw,
mmc_start_idle_time_bkops);
- INIT_WORK(&card->bkops_info.poll_for_completion,
- mmc_bkops_completion_polling);
/*
* Calculate the time to start the BKOPs checking.
@@ -1462,6 +1476,22 @@
return err;
}
+int mmc_send_long_pon(struct mmc_card *card)
+{
+ int err = 0;
+ struct mmc_host *host = card->host;
+
+ mmc_claim_host(host);
+ if (card->issue_long_pon && mmc_can_poweroff_notify(card)) {
+ err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG);
+ if (err)
+ pr_warning("%s: error %d sending Long PON",
+ mmc_hostname(host), err);
+ }
+ mmc_release_host(host);
+ return err;
+}
+
/*
* Host is being removed. Free up the current card.
*/
@@ -1470,6 +1500,7 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ unregister_reboot_notifier(&host->card->reboot_notify);
mmc_remove_card(host->card);
mmc_claim_host(host);
@@ -1736,6 +1767,8 @@
mmc_init_clk_scaling(host);
+ register_reboot_notifier(&host->card->reboot_notify);
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4e76f61..91e23ca 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -187,6 +187,23 @@
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
if (data & SDIO_DRIVE_SDTD)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+
+ ret = mmc_io_rw_direct(card, 0, 0,
+ SDIO_CCCR_INTERRUPT_EXTENSION, 0, &data);
+ if (ret)
+ goto out;
+ if (data & SDIO_SUPPORT_ASYNC_INTR) {
+ if (card->host->caps2 &
+ MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) {
+ data |= SDIO_ENABLE_ASYNC_INTR;
+ ret = mmc_io_rw_direct(card, 1, 0,
+ SDIO_CCCR_INTERRUPT_EXTENSION,
+ data, NULL);
+ if (ret)
+ goto out;
+ card->cccr.async_intr_sup = 1;
+ }
+ }
}
/* if no uhs mode ensure we check for high speed */
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index caf5fe4..3986cdd 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -87,6 +87,10 @@
static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
*data);
+static void msmsdcc_msm_bus_cancel_work_and_set_vote(struct msmsdcc_host *host,
+ struct mmc_ios *ios);
+static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host);
+
static u64 dma_mask = DMA_BIT_MASK(32);
static unsigned int msmsdcc_pwrsave = 1;
@@ -2731,12 +2735,14 @@
int rc = 0;
if (enable && !atomic_read(&host->clks_on)) {
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &host->mmc->ios);
+
if (!IS_ERR_OR_NULL(host->bus_clk)) {
rc = clk_prepare_enable(host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto out;
+ goto remove_vote;
}
}
if (!IS_ERR(host->pclk)) {
@@ -2764,6 +2770,18 @@
clk_disable_unprepare(host->pclk);
if (!IS_ERR_OR_NULL(host->bus_clk))
clk_disable_unprepare(host->bus_clk);
+
+ /*
+ * If clock gating is enabled, then remove the vote
+ * immediately because clocks will be disabled only
+ * after MSM_MMC_CLK_GATE_DELAY and thus no additional
+ * delay is required to remove the bus vote.
+ */
+ if (host->mmc->clkgate_delay)
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ else
+ msmsdcc_msm_bus_queue_work(host);
+
atomic_set(&host->clks_on, 0);
}
goto out;
@@ -2774,6 +2792,8 @@
disable_bus:
if (!IS_ERR_OR_NULL(host->bus_clk))
clk_disable_unprepare(host->bus_clk);
+remove_vote:
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
out:
return rc;
}
@@ -3388,6 +3408,14 @@
(1 + ((3 * USEC_PER_SEC) /
(host->clk_rate ? host->clk_rate :
msmsdcc_get_min_sup_clk_rate(host))));
+ spin_unlock_irqrestore(&host->lock, flags);
+ /*
+ * Update bus vote incase of frequency change due to
+ * clock scaling.
+ */
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host,
+ &mmc->ios);
+ spin_lock_irqsave(&host->lock, flags);
}
/*
* give atleast 2 MCLK cycles delay for clocks
@@ -3404,7 +3432,7 @@
else
clk |= MCI_CLK_WIDEBUS_1;
- if (msmsdcc_is_pwrsave(host))
+ if (msmsdcc_is_pwrsave(host) && mmc_host_may_gate_card(host->mmc->card))
clk |= MCI_CLK_PWRSAVE;
clk |= MCI_CLK_FLOWENA;
@@ -3625,7 +3653,6 @@
return rc;
}
out:
- msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3654,7 +3681,6 @@
}
out:
- msmsdcc_msm_bus_queue_work(host);
return rc;
}
#else
@@ -3690,7 +3716,6 @@
msmsdcc_pm_qos_update_latency(host, 0);
return rc;
}
- msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3713,7 +3738,6 @@
return rc;
}
out:
- msmsdcc_msm_bus_queue_work(host);
return rc;
}
#endif
@@ -6065,6 +6089,17 @@
msmsdcc_get_min_sup_clk_rate(host)));
atomic_set(&host->clks_on, 1);
+
+ ret = msmsdcc_msm_bus_register(host);
+ if (ret)
+ goto clk_disable;
+
+ if (host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
+ msmsdcc_msm_bus_work);
+
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
+
/* Apply Hard reset to SDCC to put it in power on default state */
msmsdcc_hard_reset(host);
@@ -6077,18 +6112,10 @@
pm_qos_add_request(&host->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
- ret = msmsdcc_msm_bus_register(host);
- if (ret)
- goto pm_qos_remove;
-
- if (host->msm_bus_vote.client_handle)
- INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
- msmsdcc_msm_bus_work);
-
ret = msmsdcc_vreg_init(host, true);
if (ret) {
pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
- goto clk_disable;
+ goto pm_qos_remove;
}
@@ -6147,6 +6174,7 @@
mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
+ mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
if (plat->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -6438,12 +6466,13 @@
msmsdcc_sps_exit(host);
vreg_deinit:
msmsdcc_vreg_init(host, false);
- clk_disable:
- clk_disable_unprepare(host->clk);
- msmsdcc_msm_bus_unregister(host);
pm_qos_remove:
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ msmsdcc_msm_bus_unregister(host);
+ clk_disable:
+ clk_disable_unprepare(host->clk);
clk_put:
clk_put(host->clk);
pclk_disable:
@@ -6764,8 +6793,13 @@
}
pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
out:
- /* set bus bandwidth to 0 immediately */
- msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ /*
+ * Remove the vote immediately only if clocks are off in which
+ * case we might have queued work to remove vote but it may not
+ * be completed before runtime suspend or system suspend.
+ */
+ if (!atomic_read(&host->clks_on))
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
msmsdcc_print_pm_stats(host, start, __func__, rc);
return rc;
}
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d850782..c73bf01 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1119,6 +1119,7 @@
int len, i;
int clk_table_len;
u32 *clk_table = NULL;
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -1126,7 +1127,9 @@
goto out;
}
- pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, 0);
+ pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
+ if (gpio_is_valid(pdata->status_gpio) & !(flags & OF_GPIO_ACTIVE_LOW))
+ pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
of_property_read_u32(np, "qcom,bus-width", &bus_width);
if (bus_width == 8)
@@ -1418,10 +1421,20 @@
return;
bw = sdhci_get_bw_required(host, ios);
- if (enable)
+ if (enable) {
sdhci_msm_bus_cancel_work_and_set_vote(host, bw);
- else
- sdhci_msm_bus_queue_work(host);
+ } else {
+ /*
+ * If clock gating is enabled, then remove the vote
+ * immediately because clocks will be disabled only
+ * after SDHCI_MSM_MMC_CLK_GATE_DELAY and thus no
+ * additional delay is required to remove the bus vote.
+ */
+ if (host->mmc->clkgate_delay)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ else
+ sdhci_msm_bus_queue_work(host);
+ }
}
/* Regulator utility functions */
@@ -1942,12 +1955,15 @@
if (enable && !atomic_read(&msm_host->clks_on)) {
pr_debug("%s: request to enable clocks\n",
mmc_hostname(host->mmc));
+
+ sdhci_msm_bus_voting(host, 1);
+
if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
rc = clk_prepare_enable(msm_host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto out;
+ goto remove_vote;
}
}
if (!IS_ERR(msm_host->pclk)) {
@@ -1976,6 +1992,8 @@
clk_disable_unprepare(msm_host->pclk);
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+
+ sdhci_msm_bus_voting(host, 0);
}
atomic_set(&msm_host->clks_on, enable);
goto out;
@@ -1985,6 +2003,9 @@
disable_bus_clk:
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+remove_vote:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
out:
return rc;
}
@@ -2031,6 +2052,11 @@
}
msm_host->clk_rate = sup_clock;
host->clock = clock;
+ /*
+ * Update the bus vote in case of frequency change due to
+ * clock scaling.
+ */
+ sdhci_msm_bus_voting(host, 1);
}
}
@@ -2122,7 +2148,6 @@
.toggle_cdr = sdhci_msm_toggle_cdr,
.get_max_segments = sdhci_msm_max_segs,
.set_clock = sdhci_msm_set_clock,
- .platform_bus_voting = sdhci_msm_bus_voting,
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
.disable_data_xfer = sdhci_msm_disable_data_xfer,
@@ -2213,24 +2238,33 @@
goto pclk_disable;
}
- ret = clk_prepare_enable(msm_host->clk);
- if (ret)
- goto pclk_disable;
-
/* Set to the minimum supported clock frequency */
ret = clk_set_rate(msm_host->clk, sdhci_msm_get_min_clock(host));
if (ret) {
dev_err(&pdev->dev, "MClk rate set failed (%d)\n", ret);
- goto clk_disable;
+ goto pclk_disable;
}
+ ret = clk_prepare_enable(msm_host->clk);
+ if (ret)
+ goto pclk_disable;
+
msm_host->clk_rate = sdhci_msm_get_min_clock(host);
atomic_set(&msm_host->clks_on, 1);
+ ret = sdhci_msm_bus_register(msm_host, pdev);
+ if (ret)
+ goto clk_disable;
+
+ if (msm_host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
+ sdhci_msm_bus_work);
+ sdhci_msm_bus_voting(host, 1);
+
/* Setup regulators */
ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
if (ret) {
dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
- goto clk_disable;
+ goto bus_unregister;
}
/* Reset the core and Enable SDHC mode */
@@ -2377,14 +2411,6 @@
host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us;
- ret = sdhci_msm_bus_register(msm_host, pdev);
- if (ret)
- goto vreg_deinit;
-
- if (msm_host->msm_bus_vote.client_handle)
- INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
- sdhci_msm_bus_work);
-
init_completion(&msm_host->pwr_irq_completion);
if (gpio_is_valid(msm_host->pdata->status_gpio)) {
@@ -2393,7 +2419,7 @@
if (ret) {
dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
__func__, ret);
- goto bus_unregister;
+ goto vreg_deinit;
}
}
@@ -2436,10 +2462,12 @@
free_cd_gpio:
if (gpio_is_valid(msm_host->pdata->status_gpio))
mmc_cd_gpio_free(msm_host->mmc);
-bus_unregister:
- sdhci_msm_bus_unregister(msm_host);
vreg_deinit:
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+bus_unregister:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ sdhci_msm_bus_unregister(msm_host);
clk_disable:
if (!IS_ERR(msm_host->clk))
clk_disable_unprepare(msm_host->clk);
@@ -2495,6 +2523,16 @@
disable_irq(host->irq);
disable_irq(msm_host->pwr_irq);
+ /*
+ * Remove the vote immediately only if clocks are off in which
+ * case we might have queued work to remove vote but it may not
+ * be completed before runtime suspend or system suspend.
+ */
+ if (!atomic_read(&msm_host->clks_on)) {
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ }
+
return 0;
}
@@ -2528,9 +2566,6 @@
goto out;
}
- if (msm_host->msm_bus_vote.client_handle)
- sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
-
return sdhci_msm_runtime_suspend(dev);
out:
return ret;
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 5fda343..efa09f6 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -89,6 +89,7 @@
/* QPIC NANDc (NAND Controller) Register Set */
#define MSM_NAND_REG(info, off) (info->nand_phys + off)
+#define MSM_NAND_QPIC_VERSION(info) MSM_NAND_REG(info, 0x20100)
#define MSM_NAND_FLASH_CMD(info) MSM_NAND_REG(info, 0x30000)
#define MSM_NAND_ADDR0(info) MSM_NAND_REG(info, 0x30004)
#define MSM_NAND_ADDR1(info) MSM_NAND_REG(info, 0x30008)
@@ -138,7 +139,7 @@
#define MSM_NAND_CTRL(info) MSM_NAND_REG(info, 0x30F00)
#define BAM_MODE_EN 0
-
+#define MSM_NAND_VERSION(info) MSM_NAND_REG(info, 0x30F08)
#define MSM_NAND_READ_LOCATION_0(info) MSM_NAND_REG(info, 0x30F20)
#define MSM_NAND_READ_LOCATION_1(info) MSM_NAND_REG(info, 0x30F24)
@@ -152,6 +153,12 @@
#define MSM_NAND_CMD_BLOCK_ERASE 0x3A
#define MSM_NAND_CMD_FETCH_ID 0x0B
+/* Version Mask */
+#define MSM_NAND_VERSION_MAJOR_MASK 0xF0000000
+#define MSM_NAND_VERSION_MAJOR_SHIFT 28
+#define MSM_NAND_VERSION_MINOR_MASK 0x0FFF0000
+#define MSM_NAND_VERSION_MINOR_SHIFT 16
+
/* Structure that defines a NAND SPS command element */
struct msm_nand_sps_cmd {
struct sps_command_element ce;
@@ -623,6 +630,48 @@
uint32_t ecc_bch_cfg;
};
+struct version {
+ uint16_t nand_major;
+ uint16_t nand_minor;
+ uint16_t qpic_major;
+ uint16_t qpic_minor;
+};
+
+static int msm_nand_version_check(struct msm_nand_info *info,
+ struct version *nandc_version)
+{
+ uint32_t qpic_ver = 0, nand_ver = 0;
+ int err = 0;
+
+ /* Lookup the version to identify supported features */
+ err = msm_nand_flash_rd_reg(info, MSM_NAND_VERSION(info),
+ &nand_ver);
+ if (err) {
+ pr_err("Failed to read NAND_VERSION, err=%d\n", err);
+ goto out;
+ }
+ nandc_version->nand_major = (nand_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+ MSM_NAND_VERSION_MAJOR_SHIFT;
+ nandc_version->nand_minor = (nand_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+ MSM_NAND_VERSION_MINOR_SHIFT;
+
+ err = msm_nand_flash_rd_reg(info, MSM_NAND_QPIC_VERSION(info),
+ &qpic_ver);
+ if (err) {
+ pr_err("Failed to read QPIC_VERSION, err=%d\n", err);
+ goto out;
+ }
+ nandc_version->qpic_major = (qpic_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+ MSM_NAND_VERSION_MAJOR_SHIFT;
+ nandc_version->qpic_minor = (qpic_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+ MSM_NAND_VERSION_MINOR_SHIFT;
+ pr_info("nand_major:%d, nand_minor:%d, qpic_major:%d, qpic_minor:%d\n",
+ nandc_version->nand_major, nandc_version->nand_minor,
+ nandc_version->qpic_major, nandc_version->qpic_minor);
+out:
+ return err;
+}
+
/*
* Function to identify whether the attached NAND flash device is
* complaint to ONFI spec or not. If yes, then it reads the ONFI parameter
@@ -661,6 +710,18 @@
uint32_t flash_status;
} *dma_buffer;
+
+ /* Lookup the version to identify supported features */
+ struct version nandc_version = {0};
+
+ ret = msm_nand_version_check(info, &nandc_version);
+ if (!ret && !(nandc_version.nand_major == 1 &&
+ nandc_version.nand_minor == 1 &&
+ nandc_version.qpic_major == 1 &&
+ nandc_version.qpic_minor == 1)) {
+ ret = -EPERM;
+ goto out;
+ }
wait_event(chip->dma_wait_queue, (onfi_param_info_buf =
msm_nand_get_dma_buffer(chip, ONFI_PARAM_INFO_LENGTH)));
dma_addr_param_info = msm_virt_to_dma(chip, onfi_param_info_buf);
@@ -839,6 +900,7 @@
msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
msm_nand_release_dma_buffer(chip, onfi_param_info_buf,
ONFI_PARAM_INFO_LENGTH);
+out:
return ret;
}
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index af4fe8c..72ced9d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -161,6 +161,7 @@
BBT_AUTO_REFRESH
},
+ {"NAND 4GiB 1,8V 8-bit", 0xAC, 2048, 4096, 0x20000, 0},
{NULL,}
};
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index 5fe724e..e2bd82d 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -55,7 +55,7 @@
#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)
/* Configure device instances */
-#define RMNET_SMUX_DEVICE_COUNT (1)
+#define RMNET_SMUX_DEVICE_COUNT (2)
/* allow larger frames */
#define RMNET_DATA_LEN 2000
diff --git a/drivers/net/ethernet/msm/msm_rmnet_wwan.c b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
index f90ee3d..98bdccc 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_wwan.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
@@ -547,7 +547,7 @@
static void wwan_tx_timeout(struct net_device *dev)
{
- pr_warning("[%s] wwan_tx_timeout()\n", dev->name);
+ pr_warning("[%s] wwan_tx_timeout(), data stall in UL\n", dev->name);
}
/**
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index a75687b..e8b8fc2 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -103,6 +103,8 @@
#define CCU_PRONTO_LAST_ADDR1_OFFSET 0x10
#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
+#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
+
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
@@ -258,6 +260,7 @@
const struct dev_pm_ops *pm_ops;
int triggered;
int smd_channel_ready;
+ u32 wlan_rx_buff_count;
smd_channel_t *smd_ch;
unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned char fw_major;
@@ -977,6 +980,17 @@
return -ENODEV;
}
+u32 wcnss_get_wlan_rx_buff_count(void)
+{
+ if (penv)
+ return penv->wlan_rx_buff_count;
+ else
+ return WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+
+}
+EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
+
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -1035,6 +1049,8 @@
rc = wcnss_smd_tx(msg, rsphdr->msg_len);
if (rc < 0)
pr_err("wcnss: smd tx failed\n");
+
+ kfree(msg);
}
/* Collect calibrated data from WCNSS */
@@ -1496,7 +1512,12 @@
int size = 0;
struct resource *res;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_pronto_hw");
+ "qcom,has-pronto-hw");
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
+ penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+ }
/* make sure we are only triggered once */
if (penv->triggered)
@@ -1508,7 +1529,7 @@
if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
if (has_pronto_hw) {
has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_48mhz_xo");
+ "qcom,has-48mhz-xo");
} else {
has_48mhz_xo = pdata->has_48mhz_xo;
}
@@ -1518,7 +1539,7 @@
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");
+ "qcom,has-autodetect-xo");
}
penv->thermal_mitigation = 0;
@@ -1662,6 +1683,9 @@
{
struct platform_device *pdev;
+ if (!penv)
+ return -EFAULT;
+
/* first open is only to trigger WCNSS platform driver */
if (!penv->triggered) {
pr_info(DEVICE " triggered by userspace\n");
@@ -1689,7 +1713,7 @@
{
int rc = 0;
- if (!penv->device_opened)
+ if (!penv || !penv->device_opened)
return -EFAULT;
rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
@@ -1728,7 +1752,7 @@
int rc = 0;
int size = 0;
- if (!penv->device_opened || penv->user_cal_available)
+ if (!penv || !penv->device_opened || penv->user_cal_available)
return -EFAULT;
if (penv->user_cal_rcvd == 0 && count >= 4
diff --git a/drivers/of/of_slimbus.c b/drivers/of/of_slimbus.c
index 9692185..234a5eb 100644
--- a/drivers/of/of_slimbus.c
+++ b/drivers/of/of_slimbus.c
@@ -22,6 +22,7 @@
{
struct device_node *node;
struct slim_boardinfo *binfo = NULL;
+ struct slim_boardinfo *temp;
int n = 0;
int ret = 0;
@@ -58,14 +59,16 @@
}
memcpy(slim->e_addr, prop->value, 6);
- binfo = krealloc(binfo, (n + 1) * sizeof(struct slim_boardinfo),
+ temp = krealloc(binfo, (n + 1) * sizeof(struct slim_boardinfo),
GFP_KERNEL);
- if (!binfo) {
+ if (!temp) {
dev_err(&ctrl->dev, "out of memory");
kfree(name);
kfree(slim);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto of_slim_err;
}
+ binfo = temp;
slim->dev.of_node = of_node_get(node);
slim->name = (const char *)name;
@@ -73,13 +76,15 @@
binfo[n].slim_slave = slim;
n++;
}
- return slim_register_board_info(binfo, n);
+ ret = slim_register_board_info(binfo, n);
+ if (!ret)
+ goto of_slim_ret;
of_slim_err:
- n--;
- while (n >= 0) {
+ while (n-- > 0) {
kfree(binfo[n].slim_slave->name);
kfree(binfo[n].slim_slave);
}
+of_slim_ret:
kfree(binfo);
return ret;
}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 6495db4..67c86b9 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,12 +50,6 @@
#define IPA_AGGR_STR_IN_BYTES(str) \
(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
-/*
- * This equals a timer value of 162.56us. This value was
- * determined empirically and shows good bi-directional
- * WLAN throughputs
- */
-#define IPA_HOLB_TMR_DEFAULT_VAL 0x7f
static struct ipa_plat_drv_res ipa_res = {0, };
static struct of_device_id ipa_plat_drv_match[] = {
@@ -1603,8 +1597,6 @@
result = -ENOMEM;
goto fail_mem;
}
- ipa_ctx->hol_en = 0x1;
- ipa_ctx->hol_timer = IPA_HOLB_TMR_DEFAULT_VAL;
IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
ipa_ctx->polling_mode = polling_mode;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index 7483a72..ae59f37 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,8 +13,14 @@
#include <linux/delay.h>
#include "ipa_i.h"
+/*
+ * These values were determined empirically and shows good E2E bi-
+ * directional throughputs
+ */
#define IPA_A2_HOLB_TMR_EN 0x1
-#define IPA_A2_HOLB_TMR_DEFAULT_VAL 0xff
+#define IPA_A2_HOLB_TMR_DEFAULT_VAL 0x1ff
+#define IPA_WLAN_HOLB_TMR_EN 0x1
+#define IPA_WLAN_HOLB_TMR_DEFAULT_VAL 0x7f
static void ipa_enable_data_path(u32 clnt_hdl)
{
@@ -180,34 +186,22 @@
static void ipa_program_holb(struct ipa_ep_context *ep, int ipa_ep_idx)
{
- u32 hol_en;
- u32 hol_tmr;
+ struct ipa_ep_cfg_holb holb;
if (IPA_CLIENT_IS_PROD(ep->client))
return;
switch (ep->client) {
- case IPA_CLIENT_HSIC1_CONS:
- case IPA_CLIENT_HSIC2_CONS:
- case IPA_CLIENT_HSIC3_CONS:
- case IPA_CLIENT_HSIC4_CONS:
- hol_en = ipa_ctx->hol_en;
- hol_tmr = ipa_ctx->hol_timer;
- break;
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;
+ holb.en = IPA_A2_HOLB_TMR_EN;
+ holb.tmr_val = 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_cfg_ep_holb(ipa_ep_idx, &holb);
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index b11c7da..aaf5cc0 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -15,7 +15,7 @@
#include <linux/debugfs.h>
#include <linux/stringify.h>
#include "ipa_i.h"
-
+#include "ipa_rm_i.h"
#define IPA_MAX_MSG_LEN 4096
#define IPA_DBG_CNTR_ON 127265
@@ -94,8 +94,7 @@
static struct dentry *dent;
static struct dentry *dfile_gen_reg;
static struct dentry *dfile_ep_reg;
-static struct dentry *dfile_ep_hol_en;
-static struct dentry *dfile_ep_hol_timer;
+static struct dentry *dfile_ep_holb;
static struct dentry *dfile_hdr;
static struct dentry *dfile_ip4_rt;
static struct dentry *dfile_ip6_rt;
@@ -105,6 +104,7 @@
static struct dentry *dfile_dbg_cnt;
static struct dentry *dfile_msg;
static struct dentry *dfile_ip4_nat;
+static struct dentry *dfile_rm_stats;
static char dbg_buff[IPA_MAX_MSG_LEN];
static s8 ep_reg_idx;
@@ -147,11 +147,15 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
-static ssize_t ipa_write_ep_hol_en_reg(struct file *file,
+static ssize_t ipa_write_ep_holb(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
- u32 endp_reg_val;
+ struct ipa_ep_cfg_holb holb;
+ u32 en;
+ u32 tmr_val;
+ u32 ep_idx;
unsigned long missing;
+ char *sptr, *token;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
@@ -161,40 +165,31 @@
return -EFAULT;
dbg_buff[count] = '\0';
- if (kstrtou32(dbg_buff, 16, &endp_reg_val))
- return -EFAULT;
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ep_reg_idx),
- endp_reg_val);
+ sptr = dbg_buff;
- ipa_ctx->hol_en = endp_reg_val;
+ token = strsep(&sptr, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtou32(token, 0, &ep_idx))
+ return -EINVAL;
- return count;
-}
+ token = strsep(&sptr, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtou32(token, 0, &en))
+ return -EINVAL;
-static ssize_t ipa_write_ep_hol_timer_reg(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- u32 endp_reg_val;
- unsigned long missing;
+ token = strsep(&sptr, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtou32(token, 0, &tmr_val))
+ return -EINVAL;
- if (sizeof(dbg_buff) < count + 1)
- return -EFAULT;
+ holb.en = en;
+ holb.tmr_val = tmr_val;
- missing = copy_from_user(dbg_buff, buf, count);
- if (missing)
- return -EFAULT;
-
- dbg_buff[count] = '\0';
- if (kstrtou32(dbg_buff, 16, &endp_reg_val))
- return -EFAULT;
-
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ep_reg_idx),
- endp_reg_val);
-
- ipa_ctx->hol_timer = endp_reg_val;
+ ipa_cfg_ep_holb(ep_idx, &holb);
return count;
}
@@ -955,6 +950,20 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa_rm_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int result, nbytes, cnt = 0;
+ result = ipa_rm_stat(dbg_buff, IPA_MAX_MSG_LEN);
+ if (result < 0) {
+ nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+ "Error in printing RM stat %d\n", result);
+ cnt += nbytes;
+ } else
+ cnt += result;
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
const struct file_operations ipa_gen_reg_ops = {
.read = ipa_read_gen_reg,
};
@@ -964,11 +973,8 @@
.write = ipa_write_ep_reg,
};
-const struct file_operations ipa_ep_hol_en_ops = {
- .write = ipa_write_ep_hol_en_reg,
-};
-const struct file_operations ipa_ep_hol_timer_ops = {
- .write = ipa_write_ep_hol_timer_reg,
+const struct file_operations ipa_ep_holb_ops = {
+ .write = ipa_write_ep_holb,
};
const struct file_operations ipa_hdr_ops = {
@@ -1002,6 +1008,10 @@
.read = ipa_read_nat4,
};
+const struct file_operations ipa_rm_stats = {
+ .read = ipa_rm_read_stats,
+};
+
void ipa_debugfs_init(void)
{
const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -1029,20 +1039,13 @@
goto fail;
}
- dfile_ep_hol_en = debugfs_create_file("hol_en", write_only_mode, dent,
- 0, &ipa_ep_hol_en_ops);
- if (!dfile_ep_hol_en || IS_ERR(dfile_ep_hol_en)) {
+ dfile_ep_holb = debugfs_create_file("holb", write_only_mode, dent,
+ 0, &ipa_ep_holb_ops);
+ if (!dfile_ep_holb || IS_ERR(dfile_ep_holb)) {
IPAERR("fail to create file for debug_fs dfile_ep_hol_en\n");
goto fail;
}
- dfile_ep_hol_timer = debugfs_create_file("hol_timer", write_only_mode,
- dent, 0, &ipa_ep_hol_timer_ops);
- if (!dfile_ep_hol_timer || IS_ERR(dfile_ep_hol_timer)) {
- IPAERR("fail to create file for debug_fs dfile_ep_hol_timer\n");
- goto fail;
- }
-
dfile_hdr = debugfs_create_file("hdr", read_only_mode, dent, 0,
&ipa_hdr_ops);
if (!dfile_hdr || IS_ERR(dfile_hdr)) {
@@ -1106,6 +1109,13 @@
goto fail;
}
+ dfile_rm_stats = debugfs_create_file("rm_stats", read_only_mode,
+ dent, 0,
+ &ipa_rm_stats);
+ if (!dfile_rm_stats || IS_ERR(dfile_rm_stats)) {
+ IPAERR("fail to create file for debug_fs rm_stats\n");
+ goto fail;
+ }
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index a818931..790898a 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -350,6 +350,7 @@
enum ipa_client_type client;
struct sps_pipe *ep_hdl;
struct ipa_ep_cfg cfg;
+ struct ipa_ep_cfg_holb holb;
u32 dst_pipe_index;
u32 rt_tbl_idx;
struct sps_connect connect;
@@ -686,9 +687,6 @@
/* featurize if memory footprint becomes a concern */
struct ipa_stats stats;
void *smem_pipe_mem;
- /* store HOLB configuration for WLAN TX pipes */
- u32 hol_en;
- u32 hol_timer;
struct sk_buff_head rx_list;
};
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 88a49c4..e057c5a 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -251,7 +251,8 @@
}
result = ipa_rm_resource_producer_register(
(struct ipa_rm_resource_prod *)resource,
- reg_params);
+ reg_params,
+ true);
bail:
read_unlock(&ipa_rm_ctx->lock);
return result;
@@ -312,7 +313,8 @@
}
ipa_rm_wq_send_cmd(IPA_RM_WQ_RESOURCE_CB,
resource_name,
- event);
+ event,
+ false);
result = 0;
bail:
return result;
@@ -339,7 +341,8 @@
}
ipa_rm_resource_producer_notify_clients(
(struct ipa_rm_resource_prod *)resource,
- ipa_rm_work->event);
+ ipa_rm_work->event,
+ ipa_rm_work->notify_registered_only);
read_unlock(&ipa_rm_ctx->lock);
break;
case IPA_RM_WQ_NOTIFY_CONS:
@@ -368,12 +371,15 @@
* ipa_rm_wq_send_cmd() - send a command for deferred work
* @wq_cmd: command that should be executed
* @resource_name: resource on which command should be executed
+ * @notify_registered_only: notify only clients registered by
+ * ipa_rm_register()
*
* Returns: 0 on success, negative otherwise
*/
int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
enum ipa_rm_resource_name resource_name,
- enum ipa_rm_event event)
+ enum ipa_rm_event event,
+ bool notify_registered_only)
{
int result = -ENOMEM;
struct ipa_rm_wq_work_type *work = kzalloc(sizeof(*work), GFP_KERNEL);
@@ -382,6 +388,7 @@
work->wq_cmd = wq_cmd;
work->resource_name = resource_name;
work->event = event;
+ work->notify_registered_only = notify_registered_only;
result = queue_work(ipa_rm_ctx->ipa_rm_wq,
(struct work_struct *)work);
}
@@ -423,6 +430,46 @@
}
/**
+ * ipa_rm_stat() - print RM stat
+ * @buf: [in] The user buff used to print
+ * @size: [in] The size of buf
+ * Returns: number of bytes used on success, negative on failure
+ *
+ * This function is called by ipa_debugfs in order to receive
+ * a full picture of the current state of the RM
+ */
+
+int ipa_rm_stat(char *buf, int size)
+{
+ int i, cnt = 0, result = EINVAL;
+ struct ipa_rm_resource *resource = NULL;
+
+ if (!buf || size < 0)
+ goto bail;
+
+ read_lock(&ipa_rm_ctx->lock);
+ for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; ++i) {
+ result = ipa_rm_dep_graph_get_resource(
+ ipa_rm_ctx->dep_graph,
+ i,
+ &resource);
+ if (!result) {
+ result = ipa_rm_resource_producer_print_stat(
+ resource, buf + cnt,
+ size-cnt);
+ if (result < 0)
+ goto bail;
+ cnt += result;
+ }
+ }
+ result = cnt;
+
+bail:
+ read_unlock(&ipa_rm_ctx->lock);
+ return result;
+}
+
+/**
* ipa_rm_exit() - free all IPA RM resources
*/
void ipa_rm_exit(void)
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
index 141a442..b853e2b 100644
--- a/drivers/platform/msm/ipa/ipa_rm_i.h
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -45,20 +45,26 @@
* should be done
* @dep_graph: data structure to search for resource if exists
* @event: event to notify
+ * @notify_registered_only: notify only clients registered by
+ * ipa_rm_register()
*/
struct ipa_rm_wq_work_type {
struct work_struct work;
enum ipa_rm_wq_cmd wq_cmd;
enum ipa_rm_resource_name resource_name;
enum ipa_rm_event event;
+ bool notify_registered_only;
};
int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
enum ipa_rm_resource_name resource_name,
- enum ipa_rm_event event);
+ enum ipa_rm_event event,
+ bool notify_registered_only);
int ipa_rm_initialize(void);
+int ipa_rm_stat(char *buf, int size);
+
void ipa_rm_exit(void);
#endif /* _IPA_RM_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
index 55f8239..4beb2b8 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -167,12 +167,12 @@
bool ipa_rm_peers_list_has_last_peer(
struct ipa_rm_peers_list *peers_list)
{
- bool result = true;
+ bool result = false;
if (!peers_list)
goto bail;
read_lock(&peers_list->peers_lock);
if (peers_list->peers_count == 1)
- result = false;
+ result = true;
read_unlock(&peers_list->peers_lock);
bail:
return result;
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 8655d89..7142dc7 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -171,10 +171,13 @@
* all registered clients of given producer
* @producer: producer
* @event: event to notify
+ * @notify_registered_only: notify only clients registered by
+ * ipa_rm_register()
*/
void ipa_rm_resource_producer_notify_clients(
struct ipa_rm_resource_prod *producer,
- enum ipa_rm_event event)
+ enum ipa_rm_event event,
+ bool notify_registered_only)
{
struct ipa_rm_notification_info *reg_info, *reg_info_cloned;
struct list_head *pos, *q;
@@ -184,6 +187,8 @@
reg_info = list_entry(pos,
struct ipa_rm_notification_info,
link);
+ if (notify_registered_only && !reg_info->explicit)
+ continue;
reg_info_cloned = kzalloc(sizeof(*reg_info_cloned), GFP_ATOMIC);
if (!reg_info_cloned)
goto clone_list_failed;
@@ -224,7 +229,8 @@
rwlock_init(&(*producer)->event_listeners_lock);
INIT_LIST_HEAD(&((*producer)->event_listeners));
result = ipa_rm_resource_producer_register(*producer,
- &(create_params->reg_params));
+ &(create_params->reg_params),
+ false);
if (result)
goto register_fail;
(*resource) = (struct ipa_rm_resource *) (*producer);
@@ -391,6 +397,7 @@
* ipa_rm_resource_register() - register resource
* @resource: [in] resource
* @reg_params: [in] registration parameters
+ * @explicit: [in] registered explicitly by ipa_rm_register()
*
* Returns: 0 on success, negative on failure
*
@@ -398,7 +405,8 @@
*
*/
int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
- struct ipa_rm_register_params *reg_params)
+ struct ipa_rm_register_params *reg_params,
+ bool explicit)
{
int result = 0;
struct ipa_rm_notification_info *reg_info;
@@ -430,6 +438,7 @@
}
reg_info->reg_params.user_data = reg_params->user_data;
reg_info->reg_params.notify_cb = reg_params->notify_cb;
+ reg_info->explicit = explicit;
INIT_LIST_HEAD(®_info->link);
write_lock(&producer->event_listeners_lock);
list_add(®_info->link, &producer->event_listeners);
@@ -516,10 +525,11 @@
consumer_result = ipa_rm_resource_consumer_request(
(struct ipa_rm_resource_cons *)depends_on);
spin_lock_irqsave(&resource->state_lock, flags);
- if (consumer_result != -EINPROGRESS)
+ if (consumer_result != -EINPROGRESS) {
resource->state = prev_state;
((struct ipa_rm_resource_prod *)
resource)->pending_request--;
+ }
result = consumer_result;
break;
}
@@ -551,6 +561,9 @@
{
int result = 0;
unsigned long flags;
+ unsigned long consumer_flags;
+ bool state_changed = false;
+ bool release_consumer = false;
if (!resource || !depends_on)
return -EINVAL;
IPADBG("IPA RM: %s from %d to %d ENTER\n",
@@ -565,38 +578,60 @@
spin_lock_irqsave(&resource->state_lock, flags);
switch (resource->state) {
case IPA_RM_RELEASED:
+ break;
case IPA_RM_GRANTED:
+ release_consumer = true;
break;
case IPA_RM_RELEASE_IN_PROGRESS:
if (((struct ipa_rm_resource_prod *)
- resource)->pending_release > 0)
- ((struct ipa_rm_resource_prod *)
+ resource)->pending_release > 0)
+ ((struct ipa_rm_resource_prod *)
resource)->pending_release--;
+ spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
+ if (depends_on->state == IPA_RM_RELEASE_IN_PROGRESS &&
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_release == 0) {
+ resource->state = IPA_RM_RELEASED;
+ state_changed = true;
+ }
+ spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
break;
case IPA_RM_REQUEST_IN_PROGRESS:
+ release_consumer = true;
if (((struct ipa_rm_resource_prod *)
- resource)->pending_request > 0)
- ((struct ipa_rm_resource_prod *)
+ resource)->pending_request > 0)
+ ((struct ipa_rm_resource_prod *)
resource)->pending_request--;
+ spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
+ if (depends_on->state == IPA_RM_REQUEST_IN_PROGRESS &&
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_request == 0) {
+ resource->state = IPA_RM_GRANTED;
+ state_changed = true;
+ }
+ spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
break;
default:
result = -EINVAL;
spin_unlock_irqrestore(&resource->state_lock, flags);
goto bail;
}
- spin_unlock_irqrestore(&resource->state_lock, flags);
- if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
+ if (state_changed &&
+ ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
resource->name,
- IPA_RM_RESOURCE_RELEASED);
+ resource->state,
+ false);
result = -EINPROGRESS;
}
+ spin_unlock_irqrestore(&resource->state_lock, flags);
ipa_rm_peers_list_remove_peer(resource->peers_list,
depends_on->name);
ipa_rm_peers_list_remove_peer(depends_on->peers_list,
resource->name);
- (void) ipa_rm_resource_consumer_release(
- (struct ipa_rm_resource_cons *)depends_on);
+ if (release_consumer)
+ (void) ipa_rm_resource_consumer_release(
+ (struct ipa_rm_resource_cons *)depends_on);
IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
__func__,
resource->name,
@@ -623,8 +658,12 @@
if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
spin_lock_irqsave(&producer->resource.state_lock, flags);
producer->resource.state = IPA_RM_GRANTED;
- spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- return 0;
+ (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
+ producer->resource.name,
+ IPA_RM_RESOURCE_GRANTED,
+ true);
+ result = 0;
+ goto unlock_and_bail;
}
spin_lock_irqsave(&producer->resource.state_lock, flags);
IPADBG("IPA RM ::ipa_rm_resource_producer_request state [%d]\n",
@@ -675,10 +714,13 @@
}
}
spin_lock_irqsave(&producer->resource.state_lock, flags);
- if (producer->pending_request == 0)
+ if (producer->pending_request == 0) {
producer->resource.state = IPA_RM_GRANTED;
- spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- goto bail;
+ (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
+ producer->resource.name,
+ IPA_RM_RESOURCE_GRANTED,
+ true);
+ }
unlock_and_bail:
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
bail:
@@ -706,6 +748,10 @@
if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
spin_lock_irqsave(&producer->resource.state_lock, flags);
producer->resource.state = IPA_RM_RELEASED;
+ (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
+ producer->resource.name,
+ IPA_RM_RESOURCE_RELEASED,
+ true);
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
return 0;
}
@@ -752,10 +798,13 @@
}
}
spin_lock_irqsave(&producer->resource.state_lock, flags);
- if (producer->pending_release == 0)
+ if (producer->pending_release == 0) {
producer->resource.state = IPA_RM_RELEASED;
- spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- return result;
+ (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
+ producer->resource.name,
+ IPA_RM_RESOURCE_RELEASED,
+ true);
+ }
bail:
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
@@ -781,7 +830,8 @@
&producer->resource.state_lock, flags);
ipa_rm_resource_producer_notify_clients(
producer,
- IPA_RM_RESOURCE_GRANTED);
+ IPA_RM_RESOURCE_GRANTED,
+ false);
goto bail;
}
}
@@ -798,7 +848,8 @@
&producer->resource.state_lock, flags);
ipa_rm_resource_producer_notify_clients(
producer,
- IPA_RM_RESOURCE_RELEASED);
+ IPA_RM_RESOURCE_RELEASED,
+ false);
goto bail;
}
}
@@ -863,3 +914,197 @@
spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
return;
}
+
+/*
+ * ipa_rm_resource_producer_print_stat() - print the
+ * resource status and all his dependencies
+ *
+ * @resource: [in] Resource resource
+ * @buff: [in] The buf used to print
+ * @size: [in] Buf size
+ *
+ * Returns: number of bytes used on success, negative on failure
+ */
+
+int ipa_rm_resource_producer_print_stat(
+ struct ipa_rm_resource *resource,
+ char *buf,
+ int size){
+
+ int i, nbytes, cnt = 0;
+ unsigned long flags;
+ struct ipa_rm_resource *consumer;
+
+ if (!buf || size < 0)
+ return -EINVAL;
+ switch (resource->name) {
+ case IPA_RM_RESOURCE_BRIDGE_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "BRIDGE_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_A2_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "A2_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_USB_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "USB_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_HSIC_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "HSIC_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_STD_ECM_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "STD_ECM_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_0_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_0_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_1_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_1_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_2_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_2_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_3_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_3_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_4_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_4_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_5_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_5_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_6_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_6_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WWAN_7_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WWAN_7_PROD[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_WLAN_PROD:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "WLAN_PROD[");
+ cnt += nbytes;
+ break;
+ default:
+ return -EPERM;
+ }
+ spin_lock_irqsave(&resource->state_lock, flags);
+ switch (resource->state) {
+ case IPA_RM_RELEASED:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Released] -> ");
+ cnt += nbytes;
+ break;
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Request In Progress] -> ");
+ cnt += nbytes;
+ break;
+ case IPA_RM_GRANTED:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Granted] -> ");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Release In Progress] -> ");
+ cnt += nbytes;
+ break;
+ default:
+ spin_unlock_irqrestore(
+ &resource->state_lock,
+ flags);
+ return -EPERM;
+ }
+ spin_unlock_irqrestore(
+ &resource->state_lock,
+ flags);
+ for (i = 0; i < resource->peers_list->max_peers; ++i) {
+ consumer =
+ ipa_rm_peers_list_get_resource(
+ i,
+ resource->peers_list);
+ if (consumer) {
+ switch (consumer->name) {
+ case IPA_RM_RESOURCE_A2_CONS:
+ nbytes = scnprintf(buf + cnt,
+ size - cnt,
+ " A2_CONS[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_USB_CONS:
+ nbytes = scnprintf(buf + cnt,
+ size - cnt,
+ " USB_CONS[");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RESOURCE_HSIC_CONS:
+ nbytes = scnprintf(buf + cnt,
+ size - cnt,
+ " HSIC_CONS[");
+ cnt += nbytes;
+ break;
+ default:
+ return -EPERM;
+ }
+ spin_lock_irqsave(&consumer->state_lock, flags);
+ switch (consumer->state) {
+ case IPA_RM_RELEASED:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Released], ");
+ cnt += nbytes;
+ break;
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Request In Progress], ");
+ cnt += nbytes;
+ break;
+ case IPA_RM_GRANTED:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Granted], ");
+ cnt += nbytes;
+ break;
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "Release In Progress], ");
+ cnt += nbytes;
+ break;
+ default:
+ spin_unlock_irqrestore(
+ &consumer->state_lock,
+ flags);
+ return -EPERM;
+ }
+ spin_unlock_irqrestore(
+ &consumer->state_lock,
+ flags);
+ }
+ }
+ nbytes = scnprintf(buf + cnt, size - cnt,
+ "\n");
+ cnt += nbytes;
+ return cnt;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index 81ccc53..3fe474b 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -39,10 +39,12 @@
* struct ipa_rm_notification_info - notification information
* of IPA RM client
* @reg_params: registration parameters
+ * @explicit: registered explicitly by ipa_rm_register()
* @link: link to the list of all registered clients information
*/
struct ipa_rm_notification_info {
struct ipa_rm_register_params reg_params;
+ bool explicit;
struct list_head link;
};
@@ -102,7 +104,8 @@
int ipa_rm_resource_delete(struct ipa_rm_resource *resource);
int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
- struct ipa_rm_register_params *reg_params);
+ struct ipa_rm_register_params *reg_params,
+ bool explicit);
int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
struct ipa_rm_register_params *reg_params);
@@ -122,6 +125,12 @@
void ipa_rm_resource_producer_notify_clients(
struct ipa_rm_resource_prod *producer,
- enum ipa_rm_event event);
+ enum ipa_rm_event event,
+ bool notify_registered_only);
+
+int ipa_rm_resource_producer_print_stat(
+ struct ipa_rm_resource *resource,
+ char *buf,
+ int size);
#endif /* _IPA_RM_RESOURCE_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 046c4d4..912d93c 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -931,6 +931,73 @@
EXPORT_SYMBOL(ipa_cfg_ep_route);
/**
+ * ipa_cfg_ep_holb() - IPA end-point holb configuration
+ *
+ * If an IPA producer pipe is full, IPA HW by default will block
+ * indefinitely till space opens up. During this time no packets
+ * including those from unrelated pipes will be processed. Enabling
+ * HOLB means IPA HW will be allowed to drop packets as/when needed
+ * and indefinite blocking is avoided.
+ *
+ * @clnt_hdl: [in] opaque client handle assigned by IPA to client
+ * @ipa_ep_cfg: [in] IPA end-point configuration params
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0 ||
+ ipa_ep_cfg == NULL || ipa_ep_cfg->tmr_val > 511 ||
+ ipa_ep_cfg->en > 1) {
+ IPAERR("bad parm.\n");
+ return -EINVAL;
+ }
+
+ if (IPA_CLIENT_IS_PROD(ipa_ctx->ep[clnt_hdl].client)) {
+ IPAERR("HOLB does not apply to IPA in EP %d\n", clnt_hdl);
+ return -EINVAL;
+ }
+
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
+ IPAERR("per EP HOLB not supported\n");
+ return -EPERM;
+ } else {
+ ipa_ctx->ep[clnt_hdl].holb = *ipa_ep_cfg;
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(clnt_hdl),
+ ipa_ep_cfg->en);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(clnt_hdl),
+ ipa_ep_cfg->tmr_val);
+ IPAERR("cfg holb %u ep=%d tmr=%d\n", ipa_ep_cfg->en, clnt_hdl,
+ ipa_ep_cfg->tmr_val);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_cfg_ep_holb);
+
+/**
+ * ipa_cfg_ep_holb_by_client() - IPA end-point holb configuration
+ *
+ * Wrapper function for ipa_cfg_ep_holb() with client name instead of
+ * client handle. This function is used for clients that does not have
+ * client handle.
+ *
+ * @client: [in] client name
+ * @ipa_ep_cfg: [in] IPA end-point configuration params
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
+ const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+ return ipa_cfg_ep_holb(ipa_get_ep_mapping(ipa_ctx->mode, client),
+ ipa_ep_cfg);
+}
+EXPORT_SYMBOL(ipa_cfg_ep_holb_by_client);
+
+/**
* ipa_dump_buff_internal() - dumps buffer for debug purposes
* @base: buffer base address
* @phy_base: buffer physical base address
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/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 5f049a6..c39de83 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -94,6 +94,7 @@
u8 pipes_enabled_per_bam[MAX_BAMS];
u32 inactivity_timer_ms[MAX_BAMS];
bool is_bam_inactivity[MAX_BAMS];
+ struct completion reset_done;
};
static char *bam_enable_strings[MAX_BAMS] = {
@@ -171,6 +172,7 @@
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);
@@ -761,7 +763,7 @@
spin_lock(&usb_bam_ipa_handshake_info_lock);
/* If cable was disconnected, let disconnection seq do everything */
- if (info.disconnected) {
+ 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__);
@@ -771,7 +773,7 @@
/* 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 suspend in progress\n", __func__);
+ pr_err("%s: Bus resume in progress\n", __func__);
goto no_lpm;
}
spin_unlock(&usb_bam_ipa_handshake_info_lock);
@@ -897,6 +899,8 @@
break;
case HSIC_BAM:
+ hsic_host_dev_resumed_from_cons_request = true;
+
usb_bam_resume_hsic_host();
/*
@@ -946,13 +950,31 @@
}
spin_unlock(&usb_bam_lock);
- spin_lock(&usb_bam_ipa_handshake_info_lock);
- if (cur_bam == HSUSB_BAM && info.bus_suspend)
- queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ 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;
+ 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;
+ /* In case consumer release before resume happned */
+ hsic_host_dev_resumed_from_cons_request = false;
+ }
+ }
+
+ return 0;
}
static int hsic_cons_release_resource(void)
@@ -1043,7 +1065,7 @@
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*6))
+ USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for CONS_REQUEST\n",
__func__);
pr_err("%s: Finished waiting for CONS\n", __func__);
@@ -1314,6 +1336,9 @@
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 */
@@ -1331,8 +1356,11 @@
* and clocked on. Therefore we can now set the inactivity
* timer to the hsic bam hw.
*/
- if (ctx.inactivity_timer_ms[HSIC_BAM])
+ 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)
@@ -1345,18 +1373,6 @@
pr_debug("%s: Starting hsic full suspend sequence\n",
__func__);
- info.lpm_wait_handshake[HSIC_BAM] = true;
-
- wait_for_prod_release(HSIC_BAM);
- pr_debug("%s: complete wait on hsic producer s=%d\n",
- __func__, info.cur_prod_state[HSIC_BAM]);
-
- wait_for_cons_release(HSIC_BAM);
- pr_debug("%s: complete wait on hsic consumer s=%d\n",
- __func__, info.cur_cons_state[HSIC_BAM]);
-
- info.lpm_wait_handshake[HSIC_BAM] = false;
-
/*
* Start low power mode by releasing the device
* only in case that indeed the resources were released
@@ -1366,9 +1382,6 @@
*/
spin_lock(&usb_bam_lock);
- pr_debug("%s: goto lpm?, inactivity=%d\n",
- __func__, ctx.is_bam_inactivity[HSIC_BAM]);
-
if (info.cur_cons_state[HSIC_BAM] ==
IPA_RM_RESOURCE_RELEASED &&
info.cur_prod_state[HSIC_BAM] ==
@@ -1397,14 +1410,18 @@
return true;
}
- /* We not allow lpm, therefore renew our vote here */
+ /* We don't allow lpm, therefore renew our vote here */
if (info.in_lpm[HSIC_BAM]) {
- pr_debug("%s: Getting hsic device %x\n", __func__,
- (int)hsic_host_dev);
+ 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);
- wait_for_prod_granted(HSIC_BAM, false);
} else
spin_unlock(&usb_bam_lock);
@@ -1538,6 +1555,10 @@
}
peer_handshake_info.client_ready = ready;
+ if (peer_handshake_info.state == USB_BAM_SM_PLUG_ACKED && !ready) {
+ pr_debug("Starting reset sequence");
+ INIT_COMPLETION(ctx.reset_done);
+ }
spin_unlock(&usb_bam_peer_handshake_info_lock);
if (!queue_work(ctx.usb_bam_wq,
@@ -1652,21 +1673,28 @@
}
spin_unlock(&usb_bam_lock);
+ /* 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. Actual state will be checked
- * in msm_bam_hsic_lpm_ok() just before going to lpm.
+ * 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) {
+ 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;
}
- /* Notify about the inactivity to the USB class driver */
- if (callback)
- callback(param);
-
break;
default:
pr_err("%s: unknown usb bam event type %d\n", __func__,
@@ -1700,21 +1728,6 @@
*/
ctx.is_bam_inactivity[bam] = false;
- /*
- * In case that this wakeup event occured while we are
- * waiting to release of the resurces in order to get into
- * low power mode, just cancle the waiting.
- */
- if (info.lpm_wait_handshake[bam]) {
- pr_debug("%s: cancel waiting for lpm\n", __func__);
- if (info.cur_prod_state[bam] !=
- IPA_RM_RESOURCE_RELEASED)
- complete_all(&info.prod_released[bam]);
- if (info.cur_cons_state[bam] !=
- IPA_RM_RESOURCE_RELEASED)
- complete_all(&info.cons_released[bam]);
- }
-
queue_work(ctx.usb_bam_wq, &event_info->event_w);
}
@@ -1747,6 +1760,7 @@
case USB_BAM_SM_PLUG_ACKED:
if (!peer_handshake_info.client_ready) {
spin_unlock(&usb_bam_peer_handshake_info_lock);
+ pr_debug("Starting A2 reset sequence");
smsm_change_state(SMSM_APPS_STATE,
SMSM_USB_PLUG_UNPLUG, 0);
spin_lock(&usb_bam_peer_handshake_info_lock);
@@ -1759,6 +1773,8 @@
peer_handshake_info.reset_event.
callback(peer_handshake_info.reset_event.param);
spin_lock(&usb_bam_peer_handshake_info_lock);
+ complete_all(&ctx.reset_done);
+ pr_debug("Finished reset sequence");
peer_handshake_info.state = USB_BAM_SM_INIT;
peer_handshake_info.ack_received = 0;
}
@@ -2046,7 +2062,17 @@
}
EXPORT_SYMBOL(usb_bam_disconnect_ipa);
-int usb_bam_a2_reset(void)
+void usb_bam_reset_complete(void)
+{
+ pr_debug("Waiting for reset compelte");
+ if (wait_for_completion_interruptible_timeout(&ctx.reset_done,
+ 10*HZ) <= 0)
+ pr_warn("Timeout while waiting for reset");
+
+ pr_debug("Finished Waiting for reset complete");
+}
+
+int usb_bam_a2_reset(bool to_reconnect)
{
struct usb_bam_pipe_connect *pipe_connect;
int i;
@@ -2087,6 +2113,9 @@
if (bam != -1 && sps_device_reset(ctx.h_bam[bam]))
pr_err("%s: BAM reset failed\n", __func__);
+ if (!to_reconnect)
+ return ret;
+
/* Reconnect A2 pipes */
for (i = 0; i < ctx.max_connections; i++) {
pipe_connect = &usb_bam_connections[i];
@@ -2566,6 +2595,8 @@
spin_lock_init(&usb_bam_peer_handshake_info_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
+ init_completion(&ctx.reset_done);
+ complete(&ctx.reset_done);
ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 9b3973b..e244df4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -79,6 +79,14 @@
int last_good_ocv_uv;
};
+struct fcc_data {
+ int fcc_new;
+ int chargecycles;
+ int batt_temp;
+ int fcc_real;
+ int temp_real;
+};
+
/**
* struct pm8921_bms_chip -
* @bms_output_lock: lock to prevent concurrent bms reads
@@ -144,7 +152,16 @@
int pon_ocv_uv;
int last_cc_uah;
unsigned long tm_sec;
+
int enable_fcc_learning;
+ int min_fcc_learning_soc;
+ int min_fcc_ocv_pc;
+ int max_fcc_learning_samples;
+ struct fcc_data *fcc_table;
+ int fcc_new;
+ int start_real_soc;
+ int pc_at_start_charge;
+
int shutdown_soc;
int shutdown_iavg_ua;
struct delayed_work calculate_soc_delayed_work;
@@ -194,18 +211,28 @@
#define DEFAULT_OCV_MICROVOLTS 3900000
#define DEFAULT_CHARGE_CYCLES 0
+#define DELTA_FCC_PERCENT 5
+#define MIN_START_PERCENT_FOR_LEARNING 20
+#define MIN_START_OCV_PERCENT_FOR_LEARNING 30
+#define MAX_FCC_LEARNING_COUNT 5
+#define VALID_FCC_CHGCYL_RANGE 50
+
static int last_usb_cal_delta_uv = 1800;
module_param(last_usb_cal_delta_uv, int, 0644);
static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
static int last_charge_increase;
+static int last_fcc_update_count;
+static int max_fcc_cycles = -EINVAL;
module_param(last_chargecycles, int, 0644);
module_param(last_charge_increase, int, 0644);
+module_param(last_fcc_update_count, int, 0644);
static int calculated_soc = -EINVAL;
static int last_soc = -EINVAL;
static int last_real_fcc_mah = -EINVAL;
static int last_real_fcc_batt_temp = -EINVAL;
+static int battery_removed;
static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
unsigned long status, void *unused);
@@ -214,20 +241,20 @@
.notifier_call = pm8921_battery_gauge_alarm_notify,
};
-static int bms_ops_set(const char *val, const struct kernel_param *kp)
+static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
{
- if (*(int *)kp->arg == -EINVAL)
- return param_set_int(val, kp);
- else
- return 0;
+ return -EINVAL;
}
static struct kernel_param_ops bms_param_ops = {
- .set = bms_ops_set,
+ .set = bms_ro_ops_set,
.get = param_get_int,
};
-
+/* Make last_soc as read only as it is already calculated from shutdown_soc */
module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
+module_param_cb(battery_removed, &bms_param_ops, &battery_removed, 0644);
+module_param_cb(max_fcc_cycles, &bms_param_ops,
+ &max_fcc_cycles, 0644);
/*
* bms_fake_battery is set in setups where a battery emulator is used instead
@@ -245,11 +272,6 @@
static int bms_end_ocv_uv;
static int bms_end_cc_uah;
-static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
-{
- return -EINVAL;
-}
-
static struct kernel_param_ops bms_ro_param_ops = {
.set = bms_ro_ops_set,
.get = param_get_int,
@@ -267,6 +289,9 @@
struct single_row_lut *temp, *old;
int i, fcc, ratio;
+ if (!the_chip->enable_fcc_learning || battery_removed)
+ return;
+
if (!the_chip->fcc_temp_lut) {
pr_err("The static fcc lut table is NULL\n");
return;
@@ -301,6 +326,9 @@
{
int rc = 0;
+ if (battery_removed)
+ return rc;
+
if (last_real_fcc_mah == -EINVAL)
rc = param_set_int(val, kp);
if (rc) {
@@ -323,6 +351,9 @@
{
int rc = 0;
+ if (battery_removed)
+ return rc;
+
if (last_real_fcc_batt_temp == -EINVAL)
rc = param_set_int(val, kp);
if (rc) {
@@ -1552,33 +1583,6 @@
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
-static int calculate_real_fcc_uah(struct pm8921_bms_chip *chip,
- struct pm8921_soc_params *raw,
- int batt_temp, int chargecycles,
- int *ret_fcc_uah)
-{
- int fcc_uah, unusable_charge_uah;
- int remaining_charge_uah;
- int cc_uah;
- int real_fcc_uah;
- int rbatt;
- int iavg_ua;
-
- calculate_soc_params(chip, raw, batt_temp, chargecycles,
- &fcc_uah,
- &unusable_charge_uah,
- &remaining_charge_uah,
- &cc_uah,
- &rbatt,
- &iavg_ua);
-
- real_fcc_uah = remaining_charge_uah - cc_uah;
- *ret_fcc_uah = fcc_uah;
- pr_debug("real_fcc = %d, RC = %d CC = %d fcc = %d\n",
- real_fcc_uah, remaining_charge_uah, cc_uah, fcc_uah);
- return real_fcc_uah;
-}
-
int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
int *vbat_uv)
{
@@ -2575,6 +2579,12 @@
/* store invalid soc */
pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, 0);
+ /* fcc learning cleanup */
+ if (the_chip->enable_fcc_learning) {
+ battery_removed = 1;
+ sysfs_notify(&the_chip->dev->kobj, NULL, "fcc_data");
+ }
+
/* UUC related data is left as is - use the same historical load avg */
update_power_supply(the_chip);
}
@@ -2598,6 +2608,14 @@
int calculate_soc = 0;
struct pm8921_bms_chip *chip = the_chip;
+ /* clean up the fcc learning table */
+ if (!the_chip)
+ the_chip->adjusted_fcc_temp_lut = NULL;
+ last_fcc_update_count = 0;
+ last_real_fcc_mah = -EINVAL;
+ last_real_fcc_batt_temp = -EINVAL;
+ battery_removed = 1;
+
pr_debug("Invalidating shutdown soc - the battery was removed\n");
if (shutdown_soc_invalid)
return;
@@ -2719,6 +2737,20 @@
return calculate_fcc_uah(the_chip, batt_temp, last_chargecycles);
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
+
+static void calculate_real_soc(struct pm8921_bms_chip *chip, int *soc,
+ int batt_temp, struct pm8921_soc_params *raw, int cc_uah)
+{
+ int fcc_uah = 0, rc_uah = 0;
+
+ fcc_uah = calculate_fcc_uah(chip, batt_temp, last_chargecycles);
+ rc_uah = calculate_remaining_charge_uah(chip, raw,
+ fcc_uah, batt_temp, last_chargecycles);
+ *soc = ((rc_uah - cc_uah) * 100) / fcc_uah;
+ pr_debug("fcc = %d, rc = %d, cc = %d Real SOC = %d\n",
+ fcc_uah, rc_uah, cc_uah, *soc);
+}
+
void pm8921_bms_charging_began(void)
{
struct pm8921_soc_params raw;
@@ -2742,12 +2774,123 @@
the_chip->soc_at_cv = -EINVAL;
the_chip->prev_chg_soc = -EINVAL;
+ if (the_chip->enable_fcc_learning) {
+ calculate_real_soc(the_chip, &the_chip->start_real_soc,
+ batt_temp, &raw, bms_start_cc_uah);
+ the_chip->pc_at_start_charge =
+ interpolate_pc(the_chip->pc_temp_ocv_lut, batt_temp,
+ bms_start_ocv_uv / 1000);
+ pr_debug("Start real soc = %d, start pc = %d\n",
+ the_chip->start_real_soc, the_chip->pc_at_start_charge);
+ }
+
pr_debug("start_percent = %u%%\n", the_chip->start_percent);
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
-#define DELTA_FCC_PERCENT 3
-#define MIN_START_PERCENT_FOR_LEARNING 30
+static void invalidate_fcc(struct pm8921_bms_chip *chip)
+{
+ memset(chip->fcc_table, 0, chip->max_fcc_learning_samples *
+ sizeof(*(chip->fcc_table)));
+ last_fcc_update_count = 0;
+ chip->adjusted_fcc_temp_lut = NULL;
+ last_real_fcc_mah = -EINVAL;
+ last_real_fcc_batt_temp = -EINVAL;
+ last_chargecycles = 0;
+ last_charge_increase = 0;
+}
+
+static void update_fcc_table_for_temp(struct pm8921_bms_chip *chip,
+ int batt_temp_final)
+{
+ int i, fcc_t1, fcc_t2, fcc_final;
+ struct fcc_data *ft;
+
+ /* Interpolate all the FCC entries to the same temperature */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+ ft = &chip->fcc_table[i];
+ if (ft->batt_temp == batt_temp_final)
+ continue;
+ fcc_t1 = interpolate_fcc(chip->fcc_temp_lut, ft->batt_temp);
+ fcc_t2 = interpolate_fcc(chip->fcc_temp_lut, batt_temp_final);
+ fcc_final = (ft->fcc_new / fcc_t1) * fcc_t2;
+ ft->fcc_new = fcc_final;
+ ft->batt_temp = batt_temp_final;
+ }
+}
+
+static void update_fcc_learning_table(struct pm8921_bms_chip *chip,
+ int fcc_uah, int new_fcc_uah, int chargecycles, int batt_temp)
+{
+ int i, temp_fcc_avg = 0, new_fcc_avg = 0, temp_fcc_delta = 0, count;
+ struct fcc_data *ft;
+
+ count = last_fcc_update_count % chip->max_fcc_learning_samples;
+ ft = &chip->fcc_table[count];
+ ft->fcc_new = ft->fcc_real = new_fcc_uah;
+ ft->batt_temp = ft->temp_real = batt_temp;
+ ft->chargecycles = chargecycles;
+ chip->fcc_new = new_fcc_uah;
+ last_fcc_update_count++;
+ /* update userspace with the new data */
+ sysfs_notify(&chip->dev->kobj, NULL, "fcc_data");
+
+ pr_debug("Updated fcc table. new_fcc=%d, chargecycle=%d, temp=%d fcc_update_count=%d\n",
+ new_fcc_uah, chargecycles, batt_temp, last_fcc_update_count);
+
+ if (last_fcc_update_count < chip->max_fcc_learning_samples) {
+ pr_debug("Not enough FCC samples. Current count = %d\n",
+ last_fcc_update_count);
+ return; /* Not enough samples to update fcc */
+ }
+
+ /* reject entries if they are > 50 chargecycles apart */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+ if ((chip->fcc_table[i].chargecycles + VALID_FCC_CHGCYL_RANGE)
+ < chargecycles) {
+ pr_debug("Charge cycle too old (> %d cycles apart)\n",
+ VALID_FCC_CHGCYL_RANGE);
+ return; /* Samples old, > 50 cycles apart*/
+ }
+ }
+ /* update the fcc table for temperature difference*/
+ update_fcc_table_for_temp(chip, batt_temp);
+
+ /* Calculate the avg. and SD for all the fcc entries */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++)
+ temp_fcc_avg += chip->fcc_table[i].fcc_new;
+
+ temp_fcc_avg /= chip->max_fcc_learning_samples;
+ temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
+
+ /* fix the fcc if its an outlier i.e. > 5% of the average */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+ ft = &chip->fcc_table[i];
+ if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
+ ft->fcc_new = temp_fcc_avg;
+ new_fcc_avg += ft->fcc_new;
+ }
+ new_fcc_avg /= chip->max_fcc_learning_samples;
+
+ last_real_fcc_mah = new_fcc_avg/1000;
+ last_real_fcc_batt_temp = batt_temp;
+
+ pr_debug("FCC update: last_real_fcc_mah=%d, last_real_fcc_batt_temp=%d\n",
+ new_fcc_avg, batt_temp);
+ readjust_fcc_table();
+}
+
+static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
+{
+ /* reject the new fcc if < 50% and > 105% of nominal fcc */
+ if ((new_fcc_uah >= (fcc_uah / 2)) &&
+ ((new_fcc_uah * 100) <= (fcc_uah * 105)))
+ return true;
+
+ pr_debug("FCC rejected - not within valid limit\n");
+ return false;
+}
+
void pm8921_bms_charging_end(int is_battery_full)
{
int batt_temp;
@@ -2766,37 +2909,27 @@
bms_end_ocv_uv = raw.last_good_ocv_uv;
- if (is_battery_full && the_chip->enable_fcc_learning
- && the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
- int fcc_uah, new_fcc_uah, delta_fcc_uah;
+ pr_debug("battery_full = %d, fcc_learning = %d, pc_start_chg = %d\n",
+ is_battery_full, the_chip->enable_fcc_learning,
+ the_chip->pc_at_start_charge);
+ if (is_battery_full && the_chip->enable_fcc_learning &&
+ (the_chip->start_percent <= the_chip->min_fcc_learning_soc) &&
+ (the_chip->pc_at_start_charge <= the_chip->min_fcc_ocv_pc)) {
- new_fcc_uah = calculate_real_fcc_uah(the_chip, &raw,
- batt_temp, last_chargecycles,
- &fcc_uah);
- delta_fcc_uah = new_fcc_uah - fcc_uah;
- if (delta_fcc_uah < 0)
- delta_fcc_uah = -delta_fcc_uah;
+ int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
+ /* new_fcc = (cc_end - cc_start) / (end_soc - start_soc) */
+ delta_soc = 100 - the_chip->start_real_soc;
+ delta_cc_uah = abs(bms_end_cc_uah - bms_start_cc_uah);
+ new_fcc_uah = div_u64(delta_cc_uah * 100, delta_soc);
- if (delta_fcc_uah * 100 > (DELTA_FCC_PERCENT * fcc_uah)) {
- /* new_fcc_uah is outside the scope limit it */
- if (new_fcc_uah > fcc_uah)
- new_fcc_uah
- = (fcc_uah +
- (DELTA_FCC_PERCENT * fcc_uah) / 100);
- else
- new_fcc_uah
- = (fcc_uah -
- (DELTA_FCC_PERCENT * fcc_uah) / 100);
-
- pr_debug("delta_fcc=%d > %d percent of fcc=%d"
- "restring it to %d\n",
- delta_fcc_uah, DELTA_FCC_PERCENT,
- fcc_uah, new_fcc_uah);
- }
-
- last_real_fcc_mah = new_fcc_uah/1000;
- last_real_fcc_batt_temp = batt_temp;
- readjust_fcc_table();
+ fcc_uah = calculate_fcc_uah(the_chip, batt_temp,
+ last_chargecycles);
+ pr_info("start_real_soc = %d, end_real_soc = 100, start_cc = %d, end_cc = %d, nominal_fcc = %d, new_fcc = %d\n",
+ the_chip->start_real_soc, bms_start_cc_uah,
+ bms_end_cc_uah, fcc_uah, new_fcc_uah);
+ if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
+ update_fcc_learning_table(the_chip, fcc_uah,
+ new_fcc_uah, last_chargecycles, batt_temp);
}
if (is_battery_full) {
@@ -3350,6 +3483,127 @@
}
}
+static ssize_t fcc_data_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+ static int i;
+ int fcc_new = 0, rc;
+
+ if (battery_removed) {
+ pr_debug("Invalid FCC table. Possible battery removal\n");
+ last_fcc_update_count = 0;
+ return count;
+ }
+
+ i %= chip->max_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &fcc_new);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].fcc_new = fcc_new;
+ chip->fcc_table[i].fcc_real = fcc_new;
+ pr_debug("Rcvd: [%d] fcc_new=%d\n", i, fcc_new);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_data_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int count = 0;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ if (battery_removed) {
+ pr_debug("Invalidate the fcc table\n");
+ invalidate_fcc(chip);
+ battery_removed = 0;
+ return count;
+ }
+
+ count = snprintf(buf, PAGE_SIZE, "%d", chip->fcc_new);
+
+ pr_debug("Sent: fcc_new=%d\n", chip->fcc_new);
+
+ return count;
+}
+
+static ssize_t fcc_temp_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ static int i;
+ int batt_temp = 0, rc;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ i %= chip->max_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &batt_temp);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].batt_temp = batt_temp;
+ chip->fcc_table[i].temp_real = batt_temp;
+ pr_debug("Rcvd: [%d] batt_temp=%d\n", i, batt_temp);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_chgcyl_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ static int i;
+ int chargecycle = 0, rc;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ i %= chip->max_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &chargecycle);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].chargecycles = chargecycle;
+ pr_debug("Rcvd: [%d] chargecycle=%d\n", i, chargecycle);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_list_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+ struct fcc_data *ft;
+ int i = 0, j, count = 0;
+
+ if (last_fcc_update_count < chip->max_fcc_learning_samples)
+ i = last_fcc_update_count;
+ else
+ i = chip->max_fcc_learning_samples;
+
+ for (j = 0; j < i; j++) {
+ ft = &chip->fcc_table[j];
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %d %d %d %d\n", ft->fcc_new, ft->chargecycles,
+ ft->batt_temp, ft->fcc_real, ft->temp_real);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(fcc_data, 0664, fcc_data_get, fcc_data_set);
+static DEVICE_ATTR(fcc_temp, 0664, NULL, fcc_temp_set);
+static DEVICE_ATTR(fcc_chgcyl, 0664, NULL, fcc_chgcyl_set);
+static DEVICE_ATTR(fcc_list, 0664, fcc_list_get, NULL);
+
+static struct attribute *fcc_attrs[] = {
+ &dev_attr_fcc_data.attr,
+ &dev_attr_fcc_temp.attr,
+ &dev_attr_fcc_chgcyl.attr,
+ &dev_attr_fcc_list.attr,
+ NULL
+};
+
+static const struct attribute_group fcc_attr_group = {
+ .attrs = fcc_attrs,
+};
+
#define REG_SBI_CONFIG 0x04F
#define PAGE3_ENABLE_MASK 0x6
#define PROGRAM_REV_MASK 0x0F
@@ -3477,6 +3731,34 @@
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->enable_fcc_learning = pdata->enable_fcc_learning;
+ chip->min_fcc_learning_soc = pdata->min_fcc_learning_soc;
+ chip->min_fcc_ocv_pc = pdata->min_fcc_ocv_pc;
+ chip->max_fcc_learning_samples = pdata->max_fcc_learning_samples;
+ if (chip->enable_fcc_learning) {
+ if (!chip->min_fcc_learning_soc)
+ chip->min_fcc_learning_soc =
+ MIN_START_PERCENT_FOR_LEARNING;
+ if (!chip->min_fcc_ocv_pc)
+ chip->min_fcc_ocv_pc =
+ MIN_START_OCV_PERCENT_FOR_LEARNING;
+ if (!chip->max_fcc_learning_samples ||
+ chip->max_fcc_learning_samples > MAX_FCC_LEARNING_COUNT)
+ chip->max_fcc_learning_samples = MAX_FCC_LEARNING_COUNT;
+
+ max_fcc_cycles = chip->max_fcc_learning_samples;
+ chip->fcc_table = kzalloc(sizeof(struct fcc_data) *
+ chip->max_fcc_learning_samples, GFP_KERNEL);
+ if (!chip->fcc_table) {
+ pr_err("Unable to allocate table for fcc learning\n");
+ rc = -ENOMEM;
+ goto free_chip;
+ }
+ rc = sysfs_create_group(&pdev->dev.kobj, &fcc_attr_group);
+ if (rc) {
+ pr_err("Unable to create sysfs entries\n");
+ goto free_chip;
+ }
+ }
chip->disable_flat_portion_ocv = pdata->disable_flat_portion_ocv;
chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 03aa280..28dd539 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -168,6 +168,7 @@
uint16_t ocv_reading_at_100;
uint16_t prev_last_good_ocv_raw;
int last_ocv_uv;
+ int charging_adjusted_ocv;
int last_ocv_temp;
int last_cc_uah;
unsigned long last_soc_change_sec;
@@ -1442,8 +1443,6 @@
int rc;
bool charging, charging_since_last_report;
- soc = chip->calculated_soc;
-
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
if (rc) {
@@ -1456,6 +1455,8 @@
batt_temp = (int)result.physical;
mutex_lock(&chip->last_soc_mutex);
+ soc = chip->calculated_soc;
+
last_change_sec = chip->last_soc_change_sec;
calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
@@ -1523,7 +1524,7 @@
soc = chip->last_soc + soc_change;
}
- if (chip->last_soc != soc)
+ if (chip->last_soc != soc && !chip->last_soc_unbound)
chip->last_soc_change_sec = last_change_sec;
pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
@@ -1549,18 +1550,18 @@
return report_cc_based_soc(chip);
}
-#define VBATT_ERROR_MARGIN 20000
+#define VDD_MAX_ERR 5000
+#define VDD_STEP_SIZE 10000
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, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
- batt_terminal_uv = vbat_uv + VBATT_ERROR_MARGIN
- + (ibat_ua * chip->r_conn_mohm) / 1000;
+ batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
if (chip->soc_at_cv == -EINVAL) {
- if (batt_terminal_uv >= chip->max_voltage_uv) {
+ if (batt_terminal_uv >= chip->max_voltage_uv - VDD_MAX_ERR) {
chip->soc_at_cv = soc;
chip->prev_chg_soc = soc;
chip->ibat_at_cv_ua = ibat_ua;
@@ -1584,7 +1585,7 @@
* if voltage lessened (possibly because of a system load)
* keep reporting the prev chg soc
*/
- if (batt_terminal_uv <= chip->prev_batt_terminal_uv) {
+ if (batt_terminal_uv <= chip->prev_batt_terminal_uv - VDD_STEP_SIZE) {
pr_debug("batt_terminal_uv %d < (max = %d - 10000); CC CHG SOC %d\n",
batt_terminal_uv, chip->prev_batt_terminal_uv,
chip->prev_chg_soc);
@@ -1599,7 +1600,9 @@
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);
+ chg_soc = bound_soc(DIV_ROUND_CLOSEST(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);
@@ -1610,9 +1613,8 @@
chip->prev_chg_soc = chg_soc;
find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
- chip->last_ocv_uv = new_ocv_uv;
- pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
- new_ocv_uv,
+ chip->charging_adjusted_ocv = new_ocv_uv;
+ pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n", new_ocv_uv,
chip->prev_chg_soc);
}
@@ -1932,9 +1934,9 @@
new_calculated_soc);
done_calculating:
+ mutex_lock(&chip->last_soc_mutex);
chip->calculated_soc = new_calculated_soc;
pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
- mutex_lock(&chip->last_soc_mutex);
if (chip->last_soc_invalid) {
chip->last_soc_invalid = false;
chip->last_soc = -EINVAL;
@@ -2286,7 +2288,13 @@
if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
chip->done_charging = true;
chip->last_soc_invalid = true;
+ } else if (chip->charging_adjusted_ocv > 0) {
+ pr_debug("Charging stopped before full, adjusted OCV = %d\n",
+ chip->charging_adjusted_ocv);
+ chip->last_ocv_uv = chip->charging_adjusted_ocv;
}
+ chip->charging_adjusted_ocv = -EINVAL;
+
mutex_unlock(&chip->last_ocv_uv_mutex);
}
@@ -3048,7 +3056,7 @@
{
int rc;
int soc_calc_period;
- int time_until_next_recalc;
+ int time_until_next_recalc = 0;
unsigned long time_since_last_recalc;
unsigned long tm_now_sec;
struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
@@ -3056,26 +3064,24 @@
rc = get_current_time(&tm_now_sec);
if (rc) {
pr_err("Could not read current time: %d\n", rc);
- } else if (tm_now_sec > chip->last_recalc_time) {
- time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
- pr_debug("Time since last recalc: %lu\n",
- time_since_last_recalc);
+ } else {
if (chip->calculated_soc < chip->low_soc_calc_threshold)
soc_calc_period = chip->low_soc_calculate_soc_ms;
else
soc_calc_period = chip->calculate_soc_ms;
-
+ time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
+ pr_debug("Time since last recalc: %lu\n",
+ time_since_last_recalc);
time_until_next_recalc = max(0, soc_calc_period
- (int)(time_since_last_recalc * 1000));
-
- if (!wake_lock_active(&chip->soc_wake_lock)
- && time_until_next_recalc == 0)
- wake_lock(&chip->soc_wake_lock);
-
- schedule_delayed_work(&chip->calculate_soc_delayed_work,
- round_jiffies_relative(msecs_to_jiffies
- (time_until_next_recalc)));
}
+
+ if (!wake_lock_active(&chip->soc_wake_lock)
+ && time_until_next_recalc == 0)
+ wake_lock(&chip->soc_wake_lock);
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (time_until_next_recalc)));
return 0;
}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a5da421..f051af2 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -285,6 +285,8 @@
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
+ int set_vddmax_mv;
+ int delta_vddmax_mv;
unsigned int warm_bat_mv;
unsigned int cool_bat_mv;
unsigned int resume_delta_mv;
@@ -320,20 +322,24 @@
{}
};
-#define BPD_MAX 3
+enum bpd_type {
+ BPD_TYPE_BAT_ID,
+ BPD_TYPE_BAT_THM,
+ BPD_TYPE_BAT_THM_BAT_ID,
+};
-static const char *bpd_list[BPD_MAX] = {
- "bpd_thm",
- "bpd_id",
- "bpd_thm_id",
+static const char * const bpd_label[] = {
+ [BPD_TYPE_BAT_ID] = "bpd_id",
+ [BPD_TYPE_BAT_THM] = "bpd_thm",
+ [BPD_TYPE_BAT_THM_BAT_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)
+ for (i = 0; i < ARRAY_SIZE(bpd_label); i++) {
+ if (strcmp(bpd_label[i], name) == 0)
return i;
}
return -EINVAL;
@@ -343,11 +349,16 @@
qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
u16 base, int count)
{
- int rc;
+ int rc = 0;
struct spmi_device *spmi = chip->spmi;
- rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val,
- count);
+ if (base == 0) {
+ pr_err("base cannot be zero base=0x%02x sid=0x%02x rc=%d\n",
+ base, spmi->sid, rc);
+ return -EINVAL;
+ }
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
if (rc) {
pr_err("SPMI read failed base=0x%02x sid=0x%02x rc=%d\n", base,
spmi->sid, rc);
@@ -360,11 +371,16 @@
qpnp_chg_write(struct qpnp_chg_chip *chip, u8 *val,
u16 base, int count)
{
- int rc;
+ int rc = 0;
struct spmi_device *spmi = chip->spmi;
- rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, val,
- count);
+ if (base == 0) {
+ pr_err("base cannot be zero base=0x%02x sid=0x%02x rc=%d\n",
+ base, spmi->sid, rc);
+ return -EINVAL;
+ }
+
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, val, count);
if (rc) {
pr_err("write failed base=0x%02x sid=0x%02x rc=%d\n",
base, spmi->sid, rc);
@@ -1497,10 +1513,11 @@
pr_err("bad mV=%d asked to set\n", voltage);
return -EINVAL;
}
+ chip->set_vddmax_mv = voltage + chip->delta_vddmax_mv;
- temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+ temp = (chip->set_vddmax_mv - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
- pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ pr_debug("voltage=%d setting %02x\n", chip->set_vddmax_mv, temp);
return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
}
@@ -1830,6 +1847,31 @@
.list_voltage = qpnp_chg_regulator_boost_list_voltage,
};
+#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX 13
+#define MAX_DELTA_VDD_MAX_MV 30
+static void
+qpnp_chg_adjust_vddmax(struct qpnp_chg_chip *chip, int vbat_mv)
+{
+ int delta_mv, closest_delta_mv, sign;
+
+ delta_mv = chip->max_voltage_mv - vbat_mv;
+ if (delta_mv > 0 && delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
+ pr_debug("vbat is not low enough to increase vdd\n");
+ return;
+ }
+
+ sign = delta_mv > 0 ? 1 : -1;
+ closest_delta_mv = ((delta_mv + sign * QPNP_CHG_V_STEP_MV / 2)
+ / QPNP_CHG_V_STEP_MV) * QPNP_CHG_V_STEP_MV;
+ pr_debug("max_voltage = %d, vbat_mv = %d, delta_mv = %d, closest = %d\n",
+ chip->max_voltage_mv, vbat_mv,
+ delta_mv, closest_delta_mv);
+ chip->delta_vddmax_mv = clamp(chip->delta_vddmax_mv + closest_delta_mv,
+ -MAX_DELTA_VDD_MAX_MV, MAX_DELTA_VDD_MAX_MV);
+ pr_debug("using delta_vddmax_mv = %d\n", chip->delta_vddmax_mv);
+ qpnp_chg_set_appropriate_vddmax(chip);
+}
+
#define CONSECUTIVE_COUNT 3
static void
qpnp_eoc_work(struct work_struct *work)
@@ -1875,12 +1917,30 @@
|| chg_sts & TRKL_CHG_ON_IRQ)) {
ibat_ma = get_prop_current_now(chip) / 1000;
vbat_mv = get_prop_battery_voltage_now(chip) / 1000;
- pr_debug("ibat_ma: %d term_current =%d\n",
- ibat_ma, chip->term_current);
- if (ibat_ma > chip->term_current) {
- pr_debug("charging but increase in current demand\n");
+
+ pr_debug("ibat_ma = %d vbat_mv = %d term_current_ma = %d\n",
+ ibat_ma, vbat_mv, chip->term_current);
+
+ if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
+ (chip->max_voltage_mv - chip->resume_delta_mv))) {
+ pr_debug("woke up too early\n");
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+ goto stop_eoc;
+ }
+
+ if (buck_sts & VDD_LOOP_IRQ)
+ qpnp_chg_adjust_vddmax(chip, vbat_mv);
+
+ if (!(buck_sts & VDD_LOOP_IRQ)) {
+ pr_debug("Not in CV\n");
count = 0;
- } else if ((ibat_ma * -1) < chip->term_current) {
+ } else if ((ibat_ma * -1) > chip->term_current) {
+ pr_debug("Not at EOC, battery current too high\n");
+ count = 0;
+ } else if (ibat_ma > 0) {
+ pr_debug("Charging but system demand increased\n");
+ count = 0;
+ } else {
if (count == CONSECUTIVE_COUNT) {
pr_info("End of Charging\n");
qpnp_chg_charge_en(chip, 0);
@@ -1892,11 +1952,6 @@
count += 1;
pr_debug("EOC count = %d\n", count);
}
- } 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");
- qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
- goto stop_eoc;
}
} else {
pr_debug("not charging\n");
@@ -2018,6 +2073,8 @@
chip->flags |= CHG_FLAGS_VCP_WA;
if (chip->type == SMBB)
chip->flags |= BOOST_FLASH_WA;
+ if (chip->type == SMBBP)
+ chip->flags |= BOOST_FLASH_WA;
}
static int
@@ -2114,7 +2171,7 @@
rc |= devm_request_irq(chip->dev,
chip->chg_vbatdet_lo.irq,
qpnp_chg_vbatdet_lo_irq_handler,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"vbat-det-lo", chip);
if (rc < 0) {
pr_err("Can't request %d vbat-det-lo: %d\n",
@@ -2300,10 +2357,20 @@
case SMBBP_BAT_IF_SUBTYPE:
case SMBCL_BAT_IF_SUBTYPE:
/* Select battery presence detection */
- if (chip->bpd_detection == 1)
+ switch (chip->bpd_detection) {
+ case BPD_TYPE_BAT_THM:
+ reg = BAT_THM_EN;
+ break;
+ case BPD_TYPE_BAT_ID:
reg = BAT_ID_EN;
- else if (chip->bpd_detection == 2)
- reg = BAT_ID_EN | BAT_THM_EN;
+ break;
+ case BPD_TYPE_BAT_THM_BAT_ID:
+ reg = BAT_THM_EN | BAT_ID_EN;
+ break;
+ default:
+ reg = BAT_THM_EN;
+ break;
+ }
rc = qpnp_chg_masked_write(chip,
chip->bat_if_base + BAT_IF_BPD_CTRL,
@@ -2363,6 +2430,7 @@
spmi_resource->of_node);
if (IS_ERR(chip->otg_vreg.rdev)) {
rc = PTR_ERR(chip->otg_vreg.rdev);
+ chip->otg_vreg.rdev = NULL;
if (rc != -EPROBE_DEFER)
pr_err("OTG reg failed, rc=%d\n", rc);
return rc;
@@ -2421,6 +2489,7 @@
spmi_resource->of_node);
if (IS_ERR(chip->boost_vreg.rdev)) {
rc = PTR_ERR(chip->boost_vreg.rdev);
+ chip->boost_vreg.rdev = NULL;
if (rc != -EPROBE_DEFER)
pr_err("boost reg failed, rc=%d\n", rc);
return rc;
@@ -2499,7 +2568,8 @@
rc = of_property_read_string(chip->spmi->dev.of_node,
"qcom,bpd-detection", &bpd);
if (rc) {
- pr_debug("no bpd-detection specified, ignored\n");
+ /* Select BAT_THM as default BPD scheme */
+ chip->bpd_detection = BPD_TYPE_BAT_THM;
} else {
chip->bpd_detection = get_bpd(bpd);
if (chip->bpd_detection < 0) {
@@ -2817,6 +2887,7 @@
qpnp_chg_charge_en(chip, !chip->charging_disabled);
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+ qpnp_chg_set_appropriate_vddmax(chip);
rc = qpnp_chg_request_irqs(chip);
if (rc) {
@@ -2846,6 +2917,8 @@
if (chip->bat_if_base)
power_supply_unregister(&chip->batt_psy);
fail_chg_enable:
+ regulator_unregister(chip->otg_vreg.rdev);
+ regulator_unregister(chip->boost_vreg.rdev);
kfree(chip->thermal_mitigation);
kfree(chip);
dev_set_drvdata(&spmi->dev, NULL);
@@ -2863,11 +2936,8 @@
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);
+ regulator_unregister(chip->otg_vreg.rdev);
+ regulator_unregister(chip->boost_vreg.rdev);
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
@@ -2880,12 +2950,14 @@
struct qpnp_chg_chip *chip = dev_get_drvdata(dev);
int rc = 0;
- rc = qpnp_chg_masked_write(chip,
- chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
- VREF_BATT_THERM_FORCE_ON,
- VREF_BATT_THERM_FORCE_ON, 1);
- if (rc)
- pr_debug("failed to force on VREF_BAT_THM rc=%d\n", rc);
+ if (chip->bat_if_base) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
+ VREF_BATT_THERM_FORCE_ON,
+ VREF_BATT_THERM_FORCE_ON, 1);
+ if (rc)
+ pr_debug("failed to force on VREF_BAT_THM rc=%d\n", rc);
+ }
return rc;
}
@@ -2895,12 +2967,14 @@
struct qpnp_chg_chip *chip = dev_get_drvdata(dev);
int rc = 0;
- rc = qpnp_chg_masked_write(chip,
- chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
- VREF_BATT_THERM_FORCE_ON,
- VREF_BAT_THM_ENABLED_FSM, 1);
- if (rc)
- pr_debug("failed to enable FSM ctrl VREF_BAT_THM rc=%d\n", rc);
+ if (chip->bat_if_base) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
+ VREF_BATT_THERM_FORCE_ON,
+ VREF_BAT_THM_ENABLED_FSM, 1);
+ if (rc)
+ pr_debug("failed to set FSM VREF_BAT_THM rc=%d\n", rc);
+ }
return rc;
}
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index bfcaebc..1d60e97 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -98,6 +98,8 @@
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
+ if (alarm_type == ANDROID_ALARM_RTC_WAKEUP)
+ set_power_on_alarm(0);
spin_unlock_irqrestore(&alarm_slock, flags);
break;
@@ -125,6 +127,10 @@
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
+ if ((alarm_type == ANDROID_ALARM_RTC_WAKEUP) &&
+ (ANDROID_ALARM_BASE_CMD(cmd) ==
+ ANDROID_ALARM_SET(0)))
+ set_power_on_alarm(new_alarm_time.tv_sec);
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 9340af7..e318ecf 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -68,6 +68,13 @@
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
+static long power_on_alarm;
+
+void set_power_on_alarm(long secs)
+{
+ power_on_alarm = secs;
+}
+
static void update_timer_locked(struct alarm_queue *base, bool head_removed)
{
@@ -486,6 +493,45 @@
return 0;
}
+static void alarm_shutdown(struct platform_device *dev)
+{
+ struct timespec wall_time;
+ struct rtc_time rtc_time;
+ struct rtc_wkalrm alarm;
+ unsigned long flags;
+ long rtc_secs, alarm_delta, alarm_time;
+ int rc;
+
+ spin_lock_irqsave(&alarm_slock, flags);
+
+ if (!power_on_alarm)
+ goto disable_alarm;
+
+ rtc_read_time(alarm_rtc_dev, &rtc_time);
+ getnstimeofday(&wall_time);
+ rtc_tm_to_time(&rtc_time, &rtc_secs);
+ alarm_delta = wall_time.tv_sec - rtc_secs;
+ alarm_time = power_on_alarm - alarm_delta;
+ if (alarm_time <= rtc_secs)
+ goto disable_alarm;
+
+ rtc_time_to_tm(alarm_time, &alarm.time);
+ alarm.enabled = 1;
+ rc = rtc_set_alarm(alarm_rtc_dev, &alarm);
+ if (rc)
+ pr_alarm(ERROR, "Unable to set power-on alarm\n");
+ else
+ pr_alarm(FLOW, "Power-on alarm set to %lu\n",
+ alarm_time);
+
+ spin_unlock_irqrestore(&alarm_slock, flags);
+ return;
+
+disable_alarm:
+ rtc_alarm_irq_enable(alarm_rtc_dev, 0);
+ spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
static struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
@@ -545,6 +591,7 @@
static struct platform_driver alarm_driver = {
.suspend = alarm_suspend,
.resume = alarm_resume,
+ .shutdown = alarm_shutdown,
.driver = {
.name = "alarm"
}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 86ae8db..6962d53 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -222,7 +221,7 @@
u8 *puc;
int ret = 0;
u8 la = txn->la;
- u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+ u8 wbuf[SLIM_MSGQ_BUF_LEN];
if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
@@ -235,17 +234,14 @@
*/
ngd_slim_runtime_resume(dev->dev);
}
- if (txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
- SLIM_MSG_MC_RECONFIGURE_NOW)) {
- if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED) {
- ret = sps_disconnect(dev->rx_msgq.sps);
- dev->use_rx_msgqs = MSM_MSGQ_RESET;
- }
- if (!ret)
- ret = msm_slim_qmi_power_request(dev, false);
- else
- pr_err("SPS pipe disconnect error:%d", ret);
- return ret;
+ if ((txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
+ SLIM_MSG_MC_RECONFIGURE_NOW)) &&
+ dev->state <= MSM_CTRL_SLEEPING) {
+ msm_slim_disconnect_endp(dev, &dev->rx_msgq,
+ &dev->use_rx_msgqs);
+ msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+ &dev->use_tx_msgqs);
+ return msm_slim_qmi_power_request(dev, false);
}
else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
return 0;
@@ -389,10 +385,19 @@
NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
if (!ret) {
int timeout = wait_for_completion_timeout(&tx_sent, HZ);
- if (!timeout)
+ if (!timeout) {
ret = -ETIMEDOUT;
- else
+ /*
+ * disconnect/recoonect pipe so that subsequent
+ * transactions don't timeout due to unavailable
+ * descriptors
+ */
+ msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+ &dev->use_tx_msgqs);
+ msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
+ } else {
ret = dev->err;
+ }
}
dev->wr_comp = NULL;
if (ret) {
@@ -469,7 +474,7 @@
struct slim_msg_txn txn;
struct slim_controller *ctrl = sb->ctrl;
DECLARE_COMPLETION_ONSTACK(done);
- u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+ u8 wbuf[SLIM_MSGQ_BUF_LEN];
*clkgear = ctrl->clkgear;
*subfrmc = 0;
@@ -631,24 +636,26 @@
return ret;
}
-static void ngd_slim_setup_rx_path(struct msm_slim_ctrl *dev)
+static void ngd_slim_setup_msg_path(struct msm_slim_ctrl *dev)
{
- int ret;
if (dev->state == MSM_CTRL_DOWN) {
msm_slim_sps_init(dev, dev->bam_mem,
NGD_BASE(dev->ctrl.nr,
dev->ver) + NGD_STATUS, true);
} else {
if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
- return;
- ret = msm_slim_connect_endp(dev, &dev->rx_msgq,
+ goto setup_tx_msg_path;
+ msm_slim_connect_endp(dev, &dev->rx_msgq,
&dev->rx_msgq_notify);
- if (!ret)
- dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
- else
- pr_err("RX msgq not being used:%d", ret);
+
+setup_tx_msg_path:
+ if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
+ return;
+ msm_slim_connect_endp(dev, &dev->tx_msgq,
+ NULL);
}
}
+
static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
{
u8 mc, mt, len;
@@ -677,9 +684,11 @@
txn.len = 4;
pr_info("SLIM SAT: Received master capability");
if (dev->state >= MSM_CTRL_ASLEEP) {
- ngd_slim_setup_rx_path(dev);
+ ngd_slim_setup_msg_path(dev);
if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
msgq_en |= NGD_CFG_RX_MSGQ_EN;
+ if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+ msgq_en |= NGD_CFG_TX_MSGQ_EN;
writel_relaxed(msgq_en, dev->base +
NGD_BASE(dev->ctrl.nr, dev->ver));
/* make sure NGD MSG-Q config goes through */
@@ -793,7 +802,7 @@
* ADSP power collapse case, where HW wasn't reset.
* Reconnect BAM pipes if disconnected
*/
- ngd_slim_setup_rx_path(dev);
+ ngd_slim_setup_msg_path(dev);
return 0;
} else if (cur_state != MSM_CTRL_DOWN) {
pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
@@ -806,6 +815,12 @@
sps_free_endpoint(endpoint->sps);
dev->use_rx_msgqs = MSM_MSGQ_RESET;
}
+ if (dev->use_tx_msgqs == MSM_MSGQ_DOWN) {
+ struct msm_slim_endp *endpoint = &dev->tx_msgq;
+ sps_disconnect(endpoint->sps);
+ sps_free_endpoint(endpoint->sps);
+ dev->use_tx_msgqs = MSM_MSGQ_RESET;
+ }
/*
* ADSP power collapse case (OR SSR), where HW was reset
* BAM programming will happen when capability message is received
@@ -957,6 +972,8 @@
/* disconnect BAM pipes */
if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
dev->use_rx_msgqs = MSM_MSGQ_DOWN;
+ if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+ dev->use_tx_msgqs = MSM_MSGQ_DOWN;
msm_slim_sps_exit(dev, false);
mutex_lock(&ctrl->m_ctrl);
/* device up should be called again after SSR */
@@ -1083,6 +1100,10 @@
dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
else
dev->use_rx_msgqs = MSM_MSGQ_RESET;
+
+ /* Enable TX message queues by default as recommended by HW */
+ dev->use_tx_msgqs = MSM_MSGQ_RESET;
+
init_completion(&dev->rx_msgq_notify);
/* Register with framework */
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 30341e2..0166196 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -269,16 +269,66 @@
return ret;
}
+/* Queue up Tx message buffer */
+static int msm_slim_post_tx_msgq(struct msm_slim_ctrl *dev, u8 *buf, int len)
+{
+ int ret;
+ struct msm_slim_endp *endpoint = &dev->tx_msgq;
+ struct sps_mem_buffer *mem = &endpoint->buf;
+ struct sps_pipe *pipe = endpoint->sps;
+ int ix = (buf - (u8 *)mem->base) / SLIM_MSGQ_BUF_LEN;
+
+ u32 phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
+
+ for (ret = 0; ret < ((len + 3) >> 2); ret++)
+ pr_debug("BAM TX buf[%d]:0x%x", ret, ((u32 *)buf)[ret]);
+
+ ret = sps_transfer_one(pipe, phys_addr, ((len + 3) & 0xFC), NULL,
+ SPS_IOVEC_FLAG_EOT);
+ if (ret)
+ dev_err(dev->dev, "transfer_one() failed 0x%x, %d\n", ret, ix);
+
+ return ret;
+}
+
+static u32 *msm_slim_tx_msgq_return(struct msm_slim_ctrl *dev)
+{
+ struct msm_slim_endp *endpoint = &dev->tx_msgq;
+ struct sps_mem_buffer *mem = &endpoint->buf;
+ struct sps_pipe *pipe = endpoint->sps;
+ struct sps_iovec iovec;
+ int ret;
+
+ /* first transaction after establishing connection */
+ if (dev->tx_idx == -1) {
+ dev->tx_idx = 0;
+ return mem->base;
+ }
+ ret = sps_get_iovec(pipe, &iovec);
+ if (ret || iovec.addr == 0) {
+ dev_err(dev->dev, "sps_get_iovec() failed 0x%x\n", ret);
+ return NULL;
+ }
+
+ /* Calculate buffer index */
+ dev->tx_idx = (iovec.addr - mem->phys_base) / SLIM_MSGQ_BUF_LEN;
+
+ return (u32 *)((u8 *)mem->base + (dev->tx_idx * SLIM_MSGQ_BUF_LEN));
+}
+
int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg)
{
- int i;
- for (i = 0; i < (len + 3) >> 2; i++) {
- dev_dbg(dev->dev, "TX data:0x%x\n", buf[i]);
- writel_relaxed(buf[i], dev->base + tx_reg + (i * 4));
+ if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED) {
+ int i;
+ for (i = 0; i < (len + 3) >> 2; i++) {
+ dev_dbg(dev->dev, "AHB TX data:0x%x\n", buf[i]);
+ writel_relaxed(buf[i], dev->base + tx_reg + (i * 4));
+ }
+ /* Guarantee that message is sent before returning */
+ mb();
+ return 0;
}
- /* Guarantee that message is sent before returning */
- mb();
- return 0;
+ return msm_slim_post_tx_msgq(dev, (u8 *)buf, len);
}
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len)
@@ -287,7 +337,10 @@
* Currently we block a transaction until the current one completes.
* In case we need multiple transactions, use message Q
*/
- return dev->tx_buf;
+ if (dev->use_tx_msgqs != MSM_MSGQ_ENABLED)
+ return dev->tx_buf;
+
+ return msm_slim_tx_msgq_return(dev);
}
static void
@@ -394,15 +447,17 @@
memset(&sps_descr_event, 0x00, sizeof(sps_descr_event));
- sps_descr_event.mode = SPS_TRIGGER_CALLBACK;
- sps_descr_event.options = SPS_O_DESC_DONE;
- sps_descr_event.user = (void *)dev;
- sps_descr_event.xfer_done = notify;
+ if (notify) {
+ sps_descr_event.mode = SPS_TRIGGER_CALLBACK;
+ sps_descr_event.options = SPS_O_DESC_DONE;
+ sps_descr_event.user = (void *)dev;
+ sps_descr_event.xfer_done = notify;
- ret = sps_register_event(endpoint->sps, &sps_descr_event);
- if (ret) {
- dev_err(dev->dev, "sps_connect() failed 0x%x\n", ret);
- goto sps_reg_event_failed;
+ ret = sps_register_event(endpoint->sps, &sps_descr_event);
+ if (ret) {
+ dev_err(dev->dev, "sps_connect() failed 0x%x\n", ret);
+ goto sps_reg_event_failed;
+ }
}
/* Register callback for errors */
@@ -423,13 +478,20 @@
* Use (buf->size/4) - 1 for the number of buffer to post
*/
- /* Setup the transfer */
- for (i = 0; i < (MSM_SLIM_DESC_NUM - 1); i++) {
- ret = msm_slim_post_rx_msgq(dev, i);
- if (ret) {
- dev_err(dev->dev, "post_rx_msgq() failed 0x%x\n", ret);
- goto sps_transfer_failed;
+ if (endpoint == &dev->rx_msgq) {
+ /* Setup the transfer */
+ for (i = 0; i < (MSM_SLIM_DESC_NUM - 1); i++) {
+ ret = msm_slim_post_rx_msgq(dev, i);
+ if (ret) {
+ dev_err(dev->dev,
+ "post_rx_msgq() failed 0x%x\n", ret);
+ goto sps_transfer_failed;
+ }
}
+ dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+ } else {
+ dev->tx_idx = -1;
+ dev->use_tx_msgqs = MSM_MSGQ_ENABLED;
}
return 0;
@@ -440,6 +502,7 @@
sps_disconnect(endpoint->sps);
return ret;
}
+
static int msm_slim_init_rx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
{
int ret;
@@ -489,10 +552,8 @@
ret = msm_slim_connect_endp(dev, endpoint, notify);
- if (!ret) {
- dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+ if (!ret)
return 0;
- }
msm_slim_sps_mem_free(dev, mem);
alloc_buffer_failed:
@@ -504,6 +565,67 @@
return ret;
}
+static int msm_slim_init_tx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
+{
+ int ret;
+ u32 pipe_offset;
+ struct msm_slim_endp *endpoint = &dev->tx_msgq;
+ struct sps_connect *config = &endpoint->config;
+ struct sps_mem_buffer *descr = &config->desc;
+ struct sps_mem_buffer *mem = &endpoint->buf;
+
+ if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
+ return 0;
+
+ /* Allocate the endpoint */
+ ret = msm_slim_init_endpoint(dev, endpoint);
+ if (ret) {
+ dev_err(dev->dev, "init_endpoint failed 0x%x\n", ret);
+ goto sps_init_endpoint_failed;
+ }
+
+ /* Get the pipe indices for the message queues */
+ pipe_offset = (readl_relaxed(dev->base + pipe_reg) & 0xfc) >> 2;
+ pipe_offset += 1;
+ dev_dbg(dev->dev, "TX Message queue pipe offset %d\n", pipe_offset);
+
+ config->mode = SPS_MODE_DEST;
+ config->source = SPS_DEV_HANDLE_MEM;
+ config->destination = dev->bam.hdl;
+ config->dest_pipe_index = pipe_offset;
+ config->src_pipe_index = 0;
+ config->options = SPS_O_ERROR | SPS_O_NO_Q |
+ SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
+
+ /* Allocate memory for the FIFO descriptors */
+ ret = msm_slim_sps_mem_alloc(dev, descr,
+ MSM_TX_BUFS * sizeof(struct sps_iovec));
+ if (ret) {
+ dev_err(dev->dev, "unable to allocate SPS descriptors\n");
+ goto alloc_descr_failed;
+ }
+
+ /* Allocate memory for the message buffer(s), N descrs, 40-byte mesg */
+ ret = msm_slim_sps_mem_alloc(dev, mem, MSM_TX_BUFS * SLIM_MSGQ_BUF_LEN);
+ if (ret) {
+ dev_err(dev->dev, "dma_alloc_coherent failed\n");
+ goto alloc_buffer_failed;
+ }
+ ret = msm_slim_connect_endp(dev, endpoint, NULL);
+
+ if (!ret)
+ return 0;
+
+ msm_slim_sps_mem_free(dev, mem);
+alloc_buffer_failed:
+ msm_slim_sps_mem_free(dev, descr);
+alloc_descr_failed:
+ msm_slim_free_endpoint(endpoint);
+sps_init_endpoint_failed:
+ dev->use_tx_msgqs = MSM_MSGQ_DISABLED;
+ return ret;
+}
+
/* Registers BAM h/w resource with SPS driver and initializes msgq endpoints */
int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
u32 pipe_reg, bool remote)
@@ -529,8 +651,10 @@
},
};
- if (dev->bam.hdl)
- goto init_rx_msgq;
+ if (dev->bam.hdl) {
+ bam_handle = dev->bam.hdl;
+ goto init_msgq;
+ }
bam_props.ee = dev->ee;
bam_props.virt_addr = dev->bam.base;
bam_props.phys_addr = bam_mem->start;
@@ -563,40 +687,68 @@
if (ret) {
dev_err(dev->dev, "disabling BAM: reg-bam failed 0x%x\n", ret);
dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
- goto init_rx_msgq;
+ dev->use_tx_msgqs = MSM_MSGQ_DISABLED;
+ return ret;
}
dev->bam.hdl = bam_handle;
dev_dbg(dev->dev, "SLIM BAM registered, handle = 0x%x\n", bam_handle);
-init_rx_msgq:
+init_msgq:
ret = msm_slim_init_rx_msgq(dev, pipe_reg);
if (ret)
dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret);
- if (ret && bam_handle) {
+ if (ret && bam_handle)
+ dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
+
+ ret = msm_slim_init_tx_msgq(dev, pipe_reg);
+ if (ret)
+ dev_err(dev->dev, "msm_slim_init_tx_msgq failed 0x%x\n", ret);
+ if (ret && bam_handle)
+ dev->use_tx_msgqs = MSM_MSGQ_DISABLED;
+
+ if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED &&
+ dev->use_rx_msgqs == MSM_MSGQ_DISABLED && bam_handle) {
sps_deregister_bam_device(bam_handle);
dev->bam.hdl = 0L;
}
+
return ret;
}
+void msm_slim_disconnect_endp(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ enum msm_slim_msgq *msgq_flag)
+{
+ if (*msgq_flag == MSM_MSGQ_ENABLED) {
+ sps_disconnect(endpoint->sps);
+ *msgq_flag = MSM_MSGQ_RESET;
+ }
+}
+
+static void msm_slim_remove_ep(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ enum msm_slim_msgq *msgq_flag)
+{
+ struct sps_connect *config = &endpoint->config;
+ struct sps_mem_buffer *descr = &config->desc;
+ struct sps_mem_buffer *mem = &endpoint->buf;
+ struct sps_register_event sps_event;
+ memset(&sps_event, 0x00, sizeof(sps_event));
+ msm_slim_sps_mem_free(dev, mem);
+ sps_register_event(endpoint->sps, &sps_event);
+ if (*msgq_flag == MSM_MSGQ_ENABLED) {
+ msm_slim_disconnect_endp(dev, endpoint, msgq_flag);
+ msm_slim_free_endpoint(endpoint);
+ }
+ msm_slim_sps_mem_free(dev, descr);
+}
+
void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
{
- if (dev->use_rx_msgqs >= MSM_MSGQ_ENABLED) {
- struct msm_slim_endp *endpoint = &dev->rx_msgq;
- struct sps_connect *config = &endpoint->config;
- struct sps_mem_buffer *descr = &config->desc;
- struct sps_mem_buffer *mem = &endpoint->buf;
- struct sps_register_event sps_event;
- memset(&sps_event, 0x00, sizeof(sps_event));
- msm_slim_sps_mem_free(dev, mem);
- sps_register_event(endpoint->sps, &sps_event);
- if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED) {
- sps_disconnect(endpoint->sps);
- msm_slim_free_endpoint(endpoint);
- dev->use_rx_msgqs = MSM_MSGQ_RESET;
- }
- msm_slim_sps_mem_free(dev, descr);
- }
+ if (dev->use_rx_msgqs >= MSM_MSGQ_ENABLED)
+ msm_slim_remove_ep(dev, &dev->rx_msgq, &dev->use_rx_msgqs);
+ if (dev->use_tx_msgqs >= MSM_MSGQ_ENABLED)
+ msm_slim_remove_ep(dev, &dev->tx_msgq, &dev->use_tx_msgqs);
if (dereg) {
sps_deregister_bam_device(dev->bam.hdl);
dev->bam.hdl = 0L;
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index cf2d26f..f8f625e 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -17,7 +17,9 @@
#include <mach/msm_qmi_interface.h>
/* Per spec.max 40 bytes per received message */
-#define SLIM_RX_MSGQ_BUF_LEN 40
+#define SLIM_MSGQ_BUF_LEN 40
+
+#define MSM_TX_BUFS 2
#define SLIM_USR_MC_GENERIC_ACK 0x25
#define SLIM_USR_MC_MASTER_CAPABILITY 0x0
@@ -200,7 +202,8 @@
u32 curr_bw;
u8 msg_cnt;
u32 tx_buf[10];
- u8 rx_msgs[MSM_CONCUR_MSG][SLIM_RX_MSGQ_BUF_LEN];
+ u8 rx_msgs[MSM_CONCUR_MSG][SLIM_MSGQ_BUF_LEN];
+ int tx_idx;
spinlock_t rx_lock;
int head;
int tail;
@@ -211,6 +214,7 @@
struct msm_slim_sat *satd[MSM_MAX_NSATS];
struct msm_slim_endp pipes[7];
struct msm_slim_sps_bam bam;
+ struct msm_slim_endp tx_msgq;
struct msm_slim_endp rx_msgq;
struct completion rx_msgq_notify;
struct task_struct *rx_msgq_thread;
@@ -219,6 +223,7 @@
struct mutex tx_lock;
u8 pgdla;
enum msm_slim_msgq use_rx_msgqs;
+ enum msm_slim_msgq use_tx_msgqs;
int pipe_b;
struct completion reconf;
bool reconf_busy;
@@ -285,6 +290,9 @@
int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
struct msm_slim_endp *endpoint,
struct completion *notify);
+void msm_slim_disconnect_endp(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ enum msm_slim_msgq *msgq_flag);
void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index c5aa7e5..1a4c3f3 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -39,11 +39,16 @@
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/atomic.h>
+#include <linux/pm_runtime.h>
#include <mach/msm_spi.h>
#include <mach/sps.h>
#include <mach/dma.h>
#include "spi_qsd.h"
+static int msm_spi_pm_resume_runtime(struct device *device);
+static int msm_spi_pm_suspend_runtime(struct device *device);
+
+
static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
struct platform_device *pdev)
{
@@ -476,6 +481,16 @@
else if (dd->mode == SPI_BAM_MODE)
spi_config |= SPI_CFG_INPUT_FIRST;
+ /*
+ * HS_MODE improves signal stability for spi-clk high rates
+ * but is invalid in LOOPBACK mode.
+ */
+ if ((dd->clock_speed >= SPI_HS_MIN_RATE) &&
+ !(dd->cur_msg->spi->mode & SPI_LOOP))
+ spi_config |= SPI_CFG_HS_MODE;
+ else
+ spi_config &= ~SPI_CFG_HS_MODE;
+
writel_relaxed(spi_config, dd->base + SPI_CONFIG);
}
@@ -859,6 +874,10 @@
u32 op, ret = IRQ_NONE;
struct msm_spi *dd = dev_id;
+ if (pm_runtime_suspended(dd->dev)) {
+ dev_warn(dd->dev, "QUP: pm runtime suspend, irq:%d\n", irq);
+ return ret;
+ }
if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
struct spi_master *master = dev_get_drvdata(dd->dev);
@@ -1705,36 +1724,22 @@
container_of(work, struct msm_spi, work_data);
unsigned long flags;
u32 status_error = 0;
- int rc = 0;
+
+ pm_runtime_get_sync(dd->dev);
mutex_lock(&dd->core_lock);
- /* Don't allow power collapse until we release mutex */
- if (pm_qos_request_active(&qos_req_list))
- pm_qos_update_request(&qos_req_list,
- dd->pm_lat);
+ /*
+ * Counter-part of system-suspend when runtime-pm is not enabled.
+ * This way, resume can be left empty and device will be put in
+ * active mode only if client requests anything on the bus
+ */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_resume_runtime(dd->dev);
+
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- /* Configure the spi clk, miso, mosi and cs gpio */
- if (dd->pdata->gpio_config) {
- rc = dd->pdata->gpio_config();
- if (rc) {
- dev_err(dd->dev,
- "%s: error configuring GPIOs\n",
- __func__);
- status_error = 1;
- }
- }
-
- rc = msm_spi_request_gpios(dd);
- if (rc)
- status_error = 1;
-
- clk_prepare_enable(dd->clk);
- clk_prepare_enable(dd->pclk);
- msm_spi_enable_irqs(dd);
-
if (!msm_spi_is_valid_state(dd)) {
dev_err(dd->dev, "%s: SPI operational state not valid\n",
__func__);
@@ -1742,6 +1747,7 @@
}
spin_lock_irqsave(&dd->queue_lock, flags);
+ dd->transfer_pending = 1;
while (!list_empty(&dd->queue)) {
dd->cur_msg = list_entry(dd->queue.next,
struct spi_message, queue);
@@ -1758,24 +1764,14 @@
dd->transfer_pending = 0;
spin_unlock_irqrestore(&dd->queue_lock, flags);
- msm_spi_disable_irqs(dd);
- clk_disable_unprepare(dd->clk);
- clk_disable_unprepare(dd->pclk);
-
- /* Free the spi clk, miso, mosi, cs gpio */
- if (!rc && dd->pdata && dd->pdata->gpio_release)
- dd->pdata->gpio_release();
- if (!rc)
- msm_spi_free_gpios(dd);
-
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
- if (pm_qos_request_active(&qos_req_list))
- pm_qos_update_request(&qos_req_list,
- PM_QOS_DEFAULT_VALUE);
-
mutex_unlock(&dd->core_lock);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+
/* If needed, this can be done after the current message is complete,
and work can be continued upon resume. No motivation for now. */
if (dd->suspended)
@@ -1789,8 +1785,6 @@
struct spi_transfer *tr;
dd = spi_master_get_devdata(spi->master);
- if (dd->suspended)
- return -EBUSY;
if (list_empty(&msg->transfers) || !msg->complete)
return -EINVAL;
@@ -1810,11 +1804,6 @@
}
spin_lock_irqsave(&dd->queue_lock, flags);
- if (dd->suspended) {
- spin_unlock_irqrestore(&dd->queue_lock, flags);
- return -EBUSY;
- }
- dd->transfer_pending = 1;
list_add_tail(&msg->queue, &dd->queue);
spin_unlock_irqrestore(&dd->queue_lock, flags);
queue_work(dd->workqueue, &dd->work_data);
@@ -1845,7 +1834,14 @@
dd = spi_master_get_devdata(spi->master);
+ pm_runtime_get_sync(dd->dev);
+
mutex_lock(&dd->core_lock);
+
+ /* Counter-part of system-suspend when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_resume_runtime(dd->dev);
+
if (dd->suspended) {
mutex_unlock(&dd->core_lock);
return -EBUSY;
@@ -1854,27 +1850,6 @@
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- /* Configure the spi clk, miso, mosi, cs gpio */
- if (dd->pdata->gpio_config) {
- rc = dd->pdata->gpio_config();
- if (rc) {
- dev_err(&spi->dev,
- "%s: error configuring GPIOs\n",
- __func__);
- rc = -ENXIO;
- goto err_setup_gpio;
- }
- }
-
- rc = msm_spi_request_gpios(dd);
- if (rc) {
- rc = -ENXIO;
- goto err_setup_gpio;
- }
-
- clk_prepare_enable(dd->clk);
- clk_prepare_enable(dd->pclk);
-
spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
if (spi->mode & SPI_CS_HIGH)
@@ -1892,18 +1867,19 @@
/* Ensure previous write completed before disabling the clocks */
mb();
- clk_disable_unprepare(dd->clk);
- clk_disable_unprepare(dd->pclk);
- /* Free the spi clk, miso, mosi, cs gpio */
- if (dd->pdata && dd->pdata->gpio_release)
- dd->pdata->gpio_release();
- msm_spi_free_gpios(dd);
-
-err_setup_gpio:
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
+
+ /* Counter-part of system-resume when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_suspend_runtime(dd->dev);
+
mutex_unlock(&dd->core_lock);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+
err_setup_exit:
return rc;
}
@@ -2729,7 +2705,7 @@
clk_enabled = 0;
pclk_enabled = 0;
- dd->suspended = 0;
+ dd->suspended = 1;
dd->transfer_pending = 0;
dd->multi_xfr = 0;
dd->mode = SPI_MODE_NONE;
@@ -2745,6 +2721,10 @@
mutex_unlock(&dd->core_lock);
locked = 0;
+ pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
rc = spi_register_master(master);
if (rc)
goto err_probe_reg_master;
@@ -2762,6 +2742,7 @@
err_attrs:
spi_unregister_master(master);
err_probe_reg_master:
+ pm_runtime_disable(&pdev->dev);
err_probe_irq:
err_probe_state:
if (dd->dma_teardown)
@@ -2795,48 +2776,130 @@
}
#ifdef CONFIG_PM
-static int msm_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int msm_spi_pm_suspend_runtime(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
struct spi_master *master = platform_get_drvdata(pdev);
- struct msm_spi *dd;
- unsigned long flags;
+ struct msm_spi *dd;
+ unsigned long flags;
+ dev_dbg(device, "pm_runtime: suspending...\n");
if (!master)
goto suspend_exit;
dd = spi_master_get_devdata(master);
if (!dd)
goto suspend_exit;
- /* Make sure nothing is added to the queue while we're suspending */
+ if (dd->suspended)
+ return 0;
+
+ /*
+ * Make sure nothing is added to the queue while we're
+ * suspending
+ */
spin_lock_irqsave(&dd->queue_lock, flags);
dd->suspended = 1;
spin_unlock_irqrestore(&dd->queue_lock, flags);
/* Wait for transactions to end, or time out */
- wait_event_interruptible(dd->continue_suspend, !dd->transfer_pending);
+ wait_event_interruptible(dd->continue_suspend,
+ !dd->transfer_pending);
+ msm_spi_disable_irqs(dd);
+ clk_disable_unprepare(dd->clk);
+ clk_disable_unprepare(dd->pclk);
+
+ /* Free the spi clk, miso, mosi, cs gpio */
+ if (dd->pdata && dd->pdata->gpio_release)
+ dd->pdata->gpio_release();
+
+ msm_spi_free_gpios(dd);
+
+ if (pm_qos_request_active(&qos_req_list))
+ pm_qos_update_request(&qos_req_list,
+ PM_QOS_DEFAULT_VALUE);
suspend_exit:
return 0;
}
-static int msm_spi_resume(struct platform_device *pdev)
+static int msm_spi_pm_resume_runtime(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
struct spi_master *master = platform_get_drvdata(pdev);
- struct msm_spi *dd;
+ struct msm_spi *dd;
+ int ret = 0;
+ dev_dbg(device, "pm_runtime: resuming...\n");
if (!master)
goto resume_exit;
dd = spi_master_get_devdata(master);
if (!dd)
goto resume_exit;
+ if (!dd->suspended)
+ return 0;
+
+ if (pm_qos_request_active(&qos_req_list))
+ pm_qos_update_request(&qos_req_list,
+ dd->pm_lat);
+
+ /* Configure the spi clk, miso, mosi and cs gpio */
+ if (dd->pdata->gpio_config) {
+ ret = dd->pdata->gpio_config();
+ if (ret) {
+ dev_err(dd->dev,
+ "%s: error configuring GPIOs\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ ret = msm_spi_request_gpios(dd);
+ if (ret)
+ return ret;
+
+ clk_prepare_enable(dd->clk);
+ clk_prepare_enable(dd->pclk);
+ msm_spi_enable_irqs(dd);
dd->suspended = 0;
resume_exit:
return 0;
}
+
+static int msm_spi_suspend(struct device *device)
+{
+ if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
+ struct platform_device *pdev = to_platform_device(device);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct msm_spi *dd;
+
+ dev_dbg(device, "system suspend");
+ if (!master)
+ goto suspend_exit;
+ dd = spi_master_get_devdata(master);
+ if (!dd)
+ goto suspend_exit;
+ msm_spi_pm_suspend_runtime(device);
+ }
+suspend_exit:
+ return 0;
+}
+
+static int msm_spi_resume(struct device *device)
+{
+ /*
+ * Rely on runtime-PM to call resume in case it is enabled
+ * Even if it's not enabled, rely on 1st client transaction to do
+ * clock ON and gpio configuration
+ */
+ dev_dbg(device, "system resume");
+ return 0;
+}
#else
#define msm_spi_suspend NULL
#define msm_spi_resume NULL
+#define msm_spi_pm_suspend_runtime NULL
+#define msm_spi_pm_resume_runtime NULL
#endif /* CONFIG_PM */
static int __devexit msm_spi_remove(struct platform_device *pdev)
@@ -2850,6 +2913,8 @@
if (dd->dma_teardown)
dd->dma_teardown(dd);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clk_put(dd->clk);
clk_put(dd->pclk);
destroy_workqueue(dd->workqueue);
@@ -2867,14 +2932,19 @@
{}
};
+static const struct dev_pm_ops msm_spi_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume)
+ SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime,
+ msm_spi_pm_resume_runtime, NULL)
+};
+
static struct platform_driver msm_spi_driver = {
.driver = {
.name = SPI_DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &msm_spi_dev_pm_ops,
.of_match_table = msm_spi_dt_match,
},
- .suspend = msm_spi_suspend,
- .resume = msm_spi_resume,
.remove = __exit_p(msm_spi_remove),
};
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index b749cc0..fd1adf0 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -72,14 +72,17 @@
#define SPI_INPUT_FIFO QSD_REG(0x0200) QUP_REG(0x0218)
#define SPI_STATE QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004)
-/* SPI_CONFIG fields */
-#define SPI_CFG_INPUT_FIRST 0x00000200
+/* QUP_CONFIG fields */
+#define SPI_CFG_N 0x0000001F
#define SPI_NO_INPUT 0x00000080
#define SPI_NO_OUTPUT 0x00000040
-#define SPI_CFG_LOOPBACK 0x00000100
-#define SPI_CFG_N 0x0000001F
#define SPI_EN_EXT_OUT_FLAG 0x00010000
+/* SPI_CONFIG fields */
+#define SPI_CFG_LOOPBACK 0x00000100
+#define SPI_CFG_INPUT_FIRST 0x00000200
+#define SPI_CFG_HS_MODE 0x00000400
+
/* SPI_IO_CONTROL fields */
#define SPI_IO_C_FORCE_CS 0x00000800
#define SPI_IO_C_CLK_IDLE_HIGH 0x00000400
@@ -143,6 +146,9 @@
#define SPI_NUM_CHIPSELECTS 4
#define SPI_SUPPORTED_MODES (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)
+/* high speed mode is when bus rate is greater then 26MHz */
+#define SPI_HS_MIN_RATE (26000000)
+
#define SPI_DELAY_THRESHOLD 1
/* Default timeout is 10 milliseconds */
#define SPI_DEFAULT_TIMEOUT 10
diff --git a/drivers/spmi/spmi-dbgfs.c b/drivers/spmi/spmi-dbgfs.c
index b825ade..27df09333 100644
--- a/drivers/spmi/spmi-dbgfs.c
+++ b/drivers/spmi/spmi-dbgfs.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
@@ -24,7 +24,6 @@
* /spmi-#
*/
-#define DEBUG
#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/kernel.h>
@@ -582,7 +581,7 @@
{
struct dentry *root, *file;
- pr_debug("Creating SPMI debugfs file-system at\n");
+ pr_debug("Creating SPMI debugfs file-system\n");
root = debugfs_create_dir(DFS_ROOT_NAME, NULL);
if (IS_ERR(root)) {
pr_err("Error creating top level directory err:%ld",
@@ -697,6 +696,41 @@
}
/*
+ * spmi_dfs_del_controller: deletes spmi controller entry
+ * @return zero on success
+ */
+int spmi_dfs_del_controller(struct spmi_controller *ctrl)
+{
+ int rc;
+ struct list_head *pos, *tmp;
+ struct spmi_ctrl_data *ctrl_data;
+
+ pr_debug("Deleting controller %s\n", ctrl->dev.kobj.name);
+
+ rc = mutex_lock_interruptible(&dbgfs_data.lock);
+ if (rc)
+ return rc;
+
+ list_for_each_safe(pos, tmp, &dbgfs_data.ctrl) {
+ ctrl_data = list_entry(pos, struct spmi_ctrl_data, node);
+
+ if (ctrl_data->ctrl == ctrl) {
+ debugfs_remove_recursive(ctrl_data->dir);
+ list_del(pos);
+ kfree(ctrl_data);
+ rc = 0;
+ goto done;
+ }
+ }
+ rc = -EINVAL;
+ pr_debug("Unknown controller %s\n", ctrl->dev.kobj.name);
+
+done:
+ mutex_unlock(&dbgfs_data.lock);
+ return rc;
+}
+
+/*
* spmi_dfs_create_file: creates a new file in the SPMI debugfs
* @returns valid dentry pointer on success or NULL
*/
diff --git a/drivers/spmi/spmi-dbgfs.h b/drivers/spmi/spmi-dbgfs.h
index 2a0d815..10e98b9 100644
--- a/drivers/spmi/spmi-dbgfs.h
+++ b/drivers/spmi/spmi-dbgfs.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
@@ -16,8 +16,10 @@
#ifdef CONFIG_DEBUG_FS
int spmi_dfs_add_controller(struct spmi_controller *ctrl);
+int spmi_dfs_del_controller(struct spmi_controller *ctrl);
#else
static int spmi_dfs_add_controller(struct spmi_controller *ctrl) { return 0; }
+static int spmi_dfs_del_controller(struct spmi_controller *ctrl) { return 0; }
#endif
struct dentry *spmi_dfs_create_file(struct spmi_controller *ctrl,
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 49a27c7..fc21fbb 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.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
@@ -31,11 +31,9 @@
static DEFINE_MUTEX(board_lock);
static LIST_HEAD(board_list);
-static LIST_HEAD(spmi_ctrl_list);
static DEFINE_IDR(ctrl_idr);
-static struct device_type spmi_ctrl_type = { 0 };
-
-#define to_spmi(dev) platform_get_drvdata(to_platform_device(dev))
+static struct device_type spmi_dev_type;
+static struct device_type spmi_ctrl_type;
/* Forward declarations */
struct bus_type spmi_bus_type;
@@ -51,14 +49,10 @@
struct spmi_controller *ctrl;
mutex_lock(&board_lock);
- list_for_each_entry(ctrl, &spmi_ctrl_list, list) {
- if (bus_num == ctrl->nr) {
- mutex_unlock(&board_lock);
- return ctrl;
- }
- }
+ ctrl = idr_find(&ctrl_idr, bus_num);
mutex_unlock(&board_lock);
- return NULL;
+
+ return ctrl;
}
EXPORT_SYMBOL_GPL(spmi_busnum_to_ctrl);
@@ -74,6 +68,9 @@
int id;
int status;
+ if (!ctrl)
+ return -EINVAL;
+
pr_debug("adding controller for bus %d (0x%p)\n", ctrl->nr, ctrl);
if (ctrl->nr & ~MAX_ID_MASK) {
@@ -90,7 +87,7 @@
mutex_lock(&board_lock);
status = idr_get_new_above(&ctrl_idr, ctrl, ctrl->nr, &id);
if (status == 0 && id != ctrl->nr) {
- status = -EAGAIN;
+ status = -EBUSY;
idr_remove(&ctrl_idr, id);
}
mutex_unlock(&board_lock);
@@ -103,18 +100,70 @@
}
EXPORT_SYMBOL_GPL(spmi_add_controller);
+/* Remove a device associated with a controller */
+static int spmi_ctrl_remove_device(struct device *dev, void *data)
+{
+ struct spmi_device *spmidev = to_spmi_device(dev);
+ struct spmi_controller *ctrl = data;
+
+ if (dev->type == &spmi_dev_type && spmidev->ctrl == ctrl)
+ spmi_remove_device(spmidev);
+
+ return 0;
+}
+
/**
* spmi_del_controller: Controller tear-down.
- * @ctrl: controller to which this device is to be added to.
+ * @ctrl: controller to be removed.
*
* Controller added with the above API is torn down using this API.
*/
int spmi_del_controller(struct spmi_controller *ctrl)
{
- return -ENXIO;
+ struct spmi_controller *found;
+
+ if (!ctrl)
+ return -EINVAL;
+
+ /* Check that the ctrl has been added */
+ mutex_lock(&board_lock);
+ found = idr_find(&ctrl_idr, ctrl->nr);
+ mutex_unlock(&board_lock);
+ if (found != ctrl)
+ return -EINVAL;
+
+ /* Remove all the clients associated with this controller */
+ mutex_lock(&board_lock);
+ bus_for_each_dev(&spmi_bus_type, NULL, ctrl, spmi_ctrl_remove_device);
+ mutex_unlock(&board_lock);
+
+ spmi_dfs_del_controller(ctrl);
+
+ mutex_lock(&board_lock);
+ idr_remove(&ctrl_idr, ctrl->nr);
+ mutex_unlock(&board_lock);
+
+ init_completion(&ctrl->dev_released);
+ device_unregister(&ctrl->dev);
+ wait_for_completion(&ctrl->dev_released);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(spmi_del_controller);
+#define spmi_ctrl_attr_gr NULL
+static void spmi_ctrl_release(struct device *dev)
+{
+ struct spmi_controller *ctrl = to_spmi_controller(dev);
+
+ complete(&ctrl->dev_released);
+}
+
+static struct device_type spmi_ctrl_type = {
+ .groups = spmi_ctrl_attr_gr,
+ .release = spmi_ctrl_release,
+};
+
#define spmi_device_attr_gr NULL
#define spmi_device_uevent NULL
static void spmi_dev_release(struct device *dev)
@@ -146,7 +195,7 @@
{
struct spmi_device *spmidev;
- if (!ctrl) {
+ if (!ctrl || !spmi_busnum_to_ctrl(ctrl->nr)) {
pr_err("Missing SPMI controller\n");
return NULL;
}
@@ -179,12 +228,15 @@
if (dev->bus != &spmi_bus_type || dev->type != &spmi_dev_type)
return NULL;
+ if (!spmidev->ctrl || !spmi_busnum_to_ctrl(spmidev->ctrl->nr))
+ return NULL;
+
return dev;
}
/**
* spmi_add_device: Add a new device without register board info.
- * @ctrl: controller to which this device is to be added to.
+ * @spmi_dev: spmi_device to be added (registered).
*
* Called when device doesn't have an explicit client-driver to be probed, or
* the client-driver is a module installed dynamically.
@@ -195,7 +247,7 @@
struct device *dev = get_valid_device(spmidev);
if (!dev) {
- pr_err("%s: invalid SPMI device\n", __func__);
+ pr_err("invalid SPMI device\n");
return -EINVAL;
}
@@ -259,7 +311,6 @@
}
EXPORT_SYMBOL_GPL(spmi_remove_device);
-/* If controller is not present, only add to boards list */
static void spmi_match_ctrl_to_boardinfo(struct spmi_controller *ctrl,
struct spmi_boardinfo *bi)
{
@@ -278,27 +329,29 @@
* @n: number of entries.
* API enumerates respective devices on corresponding controller.
* Called from board-init function.
+ * If controller is not present, only add to boards list
*/
int spmi_register_board_info(int busnum,
struct spmi_boardinfo const *info, unsigned n)
{
int i;
struct spmii_boardinfo *bi;
+ struct spmi_controller *ctrl;
bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM;
+ ctrl = spmi_busnum_to_ctrl(busnum);
+
for (i = 0; i < n; i++, bi++, info++) {
- struct spmi_controller *ctrl;
memcpy(&bi->board_info, info, sizeof(*info));
mutex_lock(&board_lock);
list_add_tail(&bi->list, &board_list);
- list_for_each_entry(ctrl, &spmi_ctrl_list, list)
- if (ctrl->nr == busnum)
- spmi_match_ctrl_to_boardinfo(ctrl,
- &bi->board_info);
+
+ if (ctrl)
+ spmi_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
mutex_unlock(&board_lock);
}
return 0;
@@ -753,10 +806,6 @@
dev_dbg(&ctrl->dev, "Bus spmi-%d registered: dev:%x\n",
ctrl->nr, (u32)&ctrl->dev);
- mutex_lock(&board_lock);
- list_add_tail(&ctrl->list, &spmi_ctrl_list);
- mutex_unlock(&board_lock);
-
spmi_dfs_add_controller(ctrl);
return 0;
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index eb3d4ca..e1e886c 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -728,10 +728,10 @@
.size = SIZE, \
};
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
+DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 64*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
static struct logger_log *get_log_from_minor(int minor)
{
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index f373422..4829b83 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -100,8 +100,8 @@
void timed_output_dev_unregister(struct timed_output_dev *tdev)
{
device_remove_file(tdev->dev, &dev_attr_enable);
- device_destroy(timed_output_class, MKDEV(0, tdev->index));
dev_set_drvdata(tdev->dev, NULL);
+ device_destroy(timed_output_class, MKDEV(0, tdev->index));
}
EXPORT_SYMBOL_GPL(timed_output_dev_unregister);
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index ab59864..03c58a2 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -608,7 +608,8 @@
return ret;
}
-static void __cpuinit do_core_control(long temp)
+#ifdef CONFIG_SMP
+static void __ref do_core_control(long temp)
{
int i = 0;
int ret = 0;
@@ -657,6 +658,12 @@
}
mutex_unlock(&core_control_mutex);
}
+#else
+static void do_core_control(long temp)
+{
+ return;
+}
+#endif
static int do_vdd_restriction(void)
{
@@ -755,7 +762,7 @@
return ret;
}
-static void __cpuinit do_freq_control(long temp)
+static void __ref do_freq_control(long temp)
{
int ret = 0;
int cpu = 0;
@@ -798,7 +805,7 @@
}
-static void __cpuinit check_temp(struct work_struct *work)
+static void __ref check_temp(struct work_struct *work)
{
static int limit_init;
struct tsens_device tsens_dev;
@@ -832,7 +839,7 @@
msecs_to_jiffies(msm_thermal_info.poll_ms));
}
-static int __cpuinit msm_thermal_cpu_callback(struct notifier_block *nfb,
+static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -894,7 +901,7 @@
* status will be carried over to the process stopping the msm_thermal, as
* we dont want to online a core and bring in the thermal issues.
*/
-static void __cpuinit disable_msm_thermal(void)
+static void __ref disable_msm_thermal(void)
{
int cpu = 0;
@@ -910,7 +917,7 @@
}
}
-static int __cpuinit set_enabled(const char *val, const struct kernel_param *kp)
+static int __ref set_enabled(const char *val, const struct kernel_param *kp)
{
int ret = 0;
@@ -935,8 +942,9 @@
MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
+#ifdef CONFIG_SMP
/* Call with core_control_mutex locked */
-static int __cpuinit update_offline_cores(int val)
+static int __ref update_offline_cores(int val)
{
int cpu = 0;
int ret = 0;
@@ -957,6 +965,12 @@
}
return ret;
}
+#else
+static int update_offline_cores(int val)
+{
+ return 0;
+}
+#endif
static ssize_t show_cc_enabled(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
@@ -964,7 +978,7 @@
return snprintf(buf, PAGE_SIZE, "%d\n", core_control_enabled);
}
-static ssize_t __cpuinit store_cc_enabled(struct kobject *kobj,
+static ssize_t __ref store_cc_enabled(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
@@ -1001,7 +1015,7 @@
return snprintf(buf, PAGE_SIZE, "%d\n", cpus_offlined);
}
-static ssize_t __cpuinit store_cpus_offlined(struct kobject *kobj,
+static ssize_t __ref store_cpus_offlined(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
@@ -1029,19 +1043,19 @@
return count;
}
-static __cpuinitdata struct kobj_attribute cc_enabled_attr =
+static __refdata struct kobj_attribute cc_enabled_attr =
__ATTR(enabled, 0644, show_cc_enabled, store_cc_enabled);
-static __cpuinitdata struct kobj_attribute cpus_offlined_attr =
+static __refdata struct kobj_attribute cpus_offlined_attr =
__ATTR(cpus_offlined, 0644, show_cpus_offlined, store_cpus_offlined);
-static __cpuinitdata struct attribute *cc_attrs[] = {
+static __refdata struct attribute *cc_attrs[] = {
&cc_enabled_attr.attr,
&cpus_offlined_attr.attr,
NULL,
};
-static __cpuinitdata struct attribute_group cc_attr_group = {
+static __refdata struct attribute_group cc_attr_group = {
.attrs = cc_attrs,
};
@@ -1079,15 +1093,15 @@
return count;
}
-static __cpuinitdata struct kobj_attribute timer_attr =
+static __refdata struct kobj_attribute timer_attr =
__ATTR(wakeup_ms, 0644, show_wakeup_ms, store_wakeup_ms);
-static __cpuinitdata struct attribute *tt_attrs[] = {
+static __refdata struct attribute *tt_attrs[] = {
&timer_attr.attr,
NULL,
};
-static __cpuinitdata struct attribute_group tt_attr_group = {
+static __refdata struct attribute_group tt_attr_group = {
.attrs = tt_attrs,
};
@@ -1176,11 +1190,13 @@
return -EINVAL;
enabled = 1;
- core_control_enabled = 1;
+ if (num_possible_cpus() > 1)
+ core_control_enabled = 1;
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
- register_cpu_notifier(&msm_thermal_cpu_notifier);
+ if (num_possible_cpus() > 1)
+ register_cpu_notifier(&msm_thermal_cpu_notifier);
return ret;
}
@@ -1435,6 +1451,8 @@
char *key = NULL;
struct device_node *child_node = NULL;
+ rails = NULL;
+
key = "qcom,vdd-restriction-temp";
ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_degC);
if (ret)
@@ -1531,6 +1549,8 @@
int j = 0;
char *key = NULL;
+ psm_rails = NULL;
+
key = "qcom,pmic-sw-mode-temp";
ret = of_property_read_u32(node, key, &data->psm_temp_degC);
if (ret)
@@ -1686,7 +1706,8 @@
int __init msm_thermal_late_init(void)
{
- msm_thermal_add_cc_nodes();
+ if (num_possible_cpus() > 1)
+ msm_thermal_add_cc_nodes();
msm_thermal_add_psm_nodes();
msm_thermal_add_vdd_rstr_nodes();
alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 890a897..4d464c1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1974,7 +1974,8 @@
switch (msm_uport->clk_state) {
case MSM_HS_CLK_OFF:
wake_lock(&msm_uport->dma_wake_lock);
- disable_irq_nosync(msm_uport->wakeup.irq);
+ if (use_low_power_wakeup(msm_uport))
+ disable_irq_nosync(msm_uport->wakeup.irq);
spin_unlock_irqrestore(&uport->lock, flags);
/* Vote for PNOC BUS Scaling */
@@ -2348,7 +2349,8 @@
free_uart_irq:
free_irq(uport->irq, msm_uport);
free_wake_irq:
- irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+ if (use_low_power_wakeup(msm_uport))
+ irq_set_irq_wake(msm_uport->wakeup.irq, 0);
sps_disconnect_rx:
if (is_blsp_uart(msm_uport))
sps_disconnect(sps_pipe_handle_rx);
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 1b3a7abe..dcbfe9a 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.c
@@ -50,6 +50,7 @@
static uint32_t smux_ctl_ch_id[] = {
SMUX_DATA_CTL_0,
+ SMUX_DATA_CTL_1,
};
#define SMUX_CTL_NUM_CHANNELS ARRAY_SIZE(smux_ctl_ch_id)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fab5219..bb2879b 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -241,7 +241,13 @@
for (i = 0; i < num; i++) {
struct dwc3_event_buffer *evt;
- evt = dwc3_alloc_one_event_buffer(dwc, length);
+ /*
+ * As SW workaround, allocate 8 bytes more than size of event
+ * buffer given to USB Controller to avoid possible memory
+ * corruption caused by event buffer overflow when Hw writes
+ * Vendor Device test event which could be of 12 bytes.
+ */
+ evt = dwc3_alloc_one_event_buffer(dwc, (length + 8));
if (IS_ERR(evt)) {
dev_err(dwc->dev, "can't allocate event buffer\n");
return PTR_ERR(evt);
@@ -276,7 +282,7 @@
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
upper_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
- evt->length & 0xffff);
+ (evt->length - 8) & 0xffff);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
@@ -421,6 +427,14 @@
reg &= ~DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
}
+ /*
+ * clear Elastic buffer mode in GUSBPIPE_CTRL(0) register, otherwise
+ * it results in high link errors and could cause SS mode transfer
+ * failure.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg &= ~DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
if (!dwc->ev_buffs) {
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 3fb89cd..5db7420 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -195,6 +195,7 @@
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
#define DWC3_GUSB3PIPECTL_DELAY_P1P2P3 (7 << 19)
#define DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET (1 << 22)
+#define DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE (1 << 0)
/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index a3b2617..be9a4b5 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -498,7 +498,7 @@
power_supply_set_supply_type(dotg->psy, power_supply_type);
- if ((dotg->charger->chg_type == DWC3_CDP_CHARGER) && mA > 2)
+ if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
mA = DWC3_IDEV_CHG_MAX;
if (dotg->charger->max_power == mA)
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index bc1fa07..36a43c3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -91,6 +91,7 @@
#include "u_uac1.c"
#include "f_uac1.c"
#endif
+#include "f_ncm.c"
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -524,7 +525,7 @@
data->opened = false;
- if (data->enabled)
+ if (data->enabled && dev)
android_disable(dev);
data->dev = NULL;
@@ -792,7 +793,103 @@
.bind_config = gps_function_bind_config,
};
+/* ncm */
+struct ncm_function_config {
+ u8 ethaddr[ETH_ALEN];
+};
+static int
+ncm_function_init(struct android_usb_function *f, struct usb_composite_dev *c)
+{
+ f->config = kzalloc(sizeof(struct ncm_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+ return 0;
+}
+
+static void ncm_function_cleanup(struct android_usb_function *f)
+{
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int
+ncm_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ncm_function_config *ncm = f->config;
+ int ret;
+
+ if (!ncm) {
+ pr_err("%s: ncm config is null\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+ ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+ ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+
+ ret = gether_setup_name(c->cdev->gadget, ncm->ethaddr, "ncm");
+ if (ret) {
+ pr_err("%s: gether setup failed err:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = ncm_bind_config(c, ncm->ethaddr);
+ if (ret) {
+ pr_err("%s: ncm bind config failed err:%d", __func__, ret);
+ gether_cleanup();
+ return ret;
+ }
+
+ return ret;
+}
+
+static void ncm_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ gether_cleanup();
+}
+
+static ssize_t ncm_ethaddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct ncm_function_config *ncm = f->config;
+ return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+ ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+}
+
+static ssize_t ncm_ethaddr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct ncm_function_config *ncm = f->config;
+
+ if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (int *)&ncm->ethaddr[0], (int *)&ncm->ethaddr[1],
+ (int *)&ncm->ethaddr[2], (int *)&ncm->ethaddr[3],
+ (int *)&ncm->ethaddr[4], (int *)&ncm->ethaddr[5]) == 6)
+ return size;
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(ncm_ethaddr, S_IRUGO | S_IWUSR, ncm_ethaddr_show,
+ ncm_ethaddr_store);
+static struct device_attribute *ncm_function_attributes[] = {
+ &dev_attr_ncm_ethaddr,
+ NULL
+};
+
+static struct android_usb_function ncm_function = {
+ .name = "ncm",
+ .init = ncm_function_init,
+ .cleanup = ncm_function_cleanup,
+ .bind_config = ncm_function_bind_config,
+ .unbind_config = ncm_function_unbind_config,
+ .attributes = ncm_function_attributes,
+};
/* ecm transport string */
static char ecm_transports[MAX_XPORT_STR_LEN];
@@ -1857,6 +1954,7 @@
&rndis_function,
&rndis_qc_function,
&ecm_function,
+ &ncm_function,
&mass_storage_function,
&accessory_function,
#ifdef CONFIG_SND_PCM
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index af82656..939eb6d 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1979,6 +1979,7 @@
for (i = 1; i < 5; i++)
mReq->ptr->page[i] = (mReq->req.dma + i * CI13XXX_PAGE_SIZE) &
~TD_RESERVED_MASK;
+ wmb();
/* Remote Wakeup */
if (udc->suspended) {
@@ -3281,7 +3282,13 @@
del_timer(&mEp->prime_timer);
mEp->prime_timer_count = 0;
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
- hw_ep_flush(mEp->num, mEp->dir);
+ /*
+ * _ep_nuke() takes care of flushing the endpoint.
+ * some function drivers expect udc to retire all
+ * pending requests upon flushing an endpoint. There
+ * is no harm in doing it.
+ */
+ _ep_nuke(mEp);
spin_unlock_irqrestore(mEp->lock, flags);
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 1530474..4c5b38d 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -57,7 +57,7 @@
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
-} __attribute__ ((packed));
+} __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */
struct ci13xxx_qh {
@@ -75,7 +75,7 @@
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
-} __attribute__ ((packed));
+} __attribute__ ((packed, aligned(4)));
/* cache of larger request's original attributes */
struct ci13xxx_multi_req {
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index e48f94c..4db4b7a 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -63,10 +63,10 @@
};
enum mbim_notify_state {
- NCM_NOTIFY_NONE,
- NCM_NOTIFY_CONNECT,
- NCM_NOTIFY_SPEED,
- NCM_NOTIFY_RESPONSE_AVAILABLE,
+ MBIM_NOTIFY_NONE,
+ MBIM_NOTIFY_CONNECT,
+ MBIM_NOTIFY_SPEED,
+ MBIM_NOTIFY_RESPONSE_AVAILABLE,
};
struct f_mbim {
@@ -95,7 +95,7 @@
u8 ctrl_id, data_id;
u8 data_alt_int;
- struct ndp_parser_opts *parser_opts;
+ struct mbim_ndp_parser_opts *parser_opts;
spinlock_t lock;
@@ -140,24 +140,24 @@
/*-------------------------------------------------------------------------*/
-#define NTB_DEFAULT_IN_SIZE (0x4000)
-#define NTB_OUT_SIZE (0x1000)
-#define NDP_IN_DIVISOR (0x4)
+#define MBIM_NTB_DEFAULT_IN_SIZE (0x4000)
+#define MBIM_NTB_OUT_SIZE (0x1000)
+#define MBIM_NDP_IN_DIVISOR (0x4)
#define NTB_DEFAULT_IN_SIZE_IPA (0x2000)
-#define NTB_OUT_SIZE_IPA (0x2000)
+#define MBIM_NTB_OUT_SIZE_IPA (0x2000)
-#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
+#define MBIM_FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
-static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
- .wLength = sizeof ntb_parameters,
- .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
- .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
- .wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
+static struct usb_cdc_ncm_ntb_parameters mbim_ntb_parameters = {
+ .wLength = sizeof mbim_ntb_parameters,
+ .bmNtbFormatsSupported = cpu_to_le16(MBIM_FORMATS_SUPPORTED),
+ .dwNtbInMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_IN_SIZE),
+ .wNdpInDivisor = cpu_to_le16(MBIM_NDP_IN_DIVISOR),
.wNdpInPayloadRemainder = cpu_to_le16(0),
.wNdpInAlignment = cpu_to_le16(4),
- .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+ .dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_OUT_SIZE),
.wNdpOutDivisor = cpu_to_le16(4),
.wNdpOutPayloadRemainder = cpu_to_le16(0),
.wNdpOutAlignment = cpu_to_le16(4),
@@ -444,7 +444,7 @@
* and switch pointers to the structures when the format is changed.
*/
-struct ndp_parser_opts {
+struct mbim_ndp_parser_opts {
u32 nth_sign;
u32 ndp_sign;
unsigned nth_size;
@@ -487,8 +487,8 @@
.next_fp_index = 2, \
}
-static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp16_opts = INIT_NDP16_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp32_opts = INIT_NDP32_OPTS;
static inline int mbim_lock(atomic_t *excl)
{
@@ -630,7 +630,7 @@
return 0;
}
- if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
+ if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) {
pr_err("dev:%p state=%d, recover!!\n", dev,
dev->not_port.notify_state);
mbim_free_ctrl_pkt(cpkt);
@@ -670,12 +670,14 @@
int ret = 0;
aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- aggr_params.dl.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
- aggr_params.dl.max_transfer_size_byte = ntb_parameters.dwNtbInMaxSize;
+ aggr_params.dl.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.dl.max_transfer_size_byte =
+ mbim_ntb_parameters.dwNtbInMaxSize;
aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- aggr_params.ul.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
- aggr_params.ul.max_transfer_size_byte = ntb_parameters.dwNtbOutMaxSize;
+ aggr_params.ul.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.ul.max_transfer_size_byte =
+ mbim_ntb_parameters.dwNtbOutMaxSize;
ret = teth_bridge_set_aggr_params(&aggr_params);
if (ret)
@@ -731,9 +733,9 @@
static inline void mbim_reset_values(struct f_mbim *mbim)
{
- mbim->parser_opts = &ndp16_opts;
+ mbim->parser_opts = &mbim_ndp16_opts;
- mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
+ mbim->ntb_input_size = MBIM_NTB_DEFAULT_IN_SIZE;
atomic_set(&mbim->online, 0);
}
@@ -809,15 +811,15 @@
switch (mbim->not_port.notify_state) {
- case NCM_NOTIFY_NONE:
+ case MBIM_NOTIFY_NONE:
if (atomic_read(&mbim->not_port.notify_count) > 0)
- pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
+ pr_err("Pending notifications in MBIM_NOTIFY_NONE\n");
else
pr_debug("No pending notifications\n");
return;
- case NCM_NOTIFY_RESPONSE_AVAILABLE:
+ case MBIM_NOTIFY_RESPONSE_AVAILABLE:
pr_debug("Notification %02x sent\n", event->bNotificationType);
if (atomic_read(&mbim->not_port.notify_count) <= 0) {
@@ -874,7 +876,7 @@
case -ECONNRESET:
case -ESHUTDOWN:
/* connection gone */
- mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
atomic_set(&mbim->not_port.notify_count, 0);
pr_info("ESHUTDOWN/ECONNRESET, connection gone");
spin_unlock(&mbim->lock);
@@ -913,7 +915,7 @@
if (req->length == 4) {
in_size = get_unaligned_le32(req->buf);
if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
- in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
goto invalid;
}
@@ -921,7 +923,7 @@
ntb = (struct mbim_ntb_input_size *)req->buf;
in_size = get_unaligned_le32(&(ntb->ntb_input_size));
if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
- in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
goto invalid;
}
@@ -1080,9 +1082,9 @@
if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
break;
- value = w_length > sizeof ntb_parameters ?
- sizeof ntb_parameters : w_length;
- memcpy(req->buf, &ntb_parameters, value);
+ value = w_length > sizeof mbim_ntb_parameters ?
+ sizeof mbim_ntb_parameters : w_length;
+ memcpy(req->buf, &mbim_ntb_parameters, value);
break;
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -1129,7 +1131,7 @@
if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
break;
- format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+ format = (mbim->parser_opts == &mbim_ndp16_opts) ? 0 : 1;
put_unaligned_le16(format, req->buf);
value = 2;
pr_debug("NTB FORMAT: sending %d\n", format);
@@ -1145,11 +1147,11 @@
break;
switch (w_value) {
case 0x0000:
- mbim->parser_opts = &ndp16_opts;
+ mbim->parser_opts = &mbim_ndp16_opts;
pr_debug("NCM16 selected\n");
break;
case 0x0001:
- mbim->parser_opts = &ndp32_opts;
+ mbim->parser_opts = &mbim_ndp32_opts;
pr_debug("NCM32 selected\n");
break;
default:
@@ -1343,7 +1345,7 @@
mbim->data_alt_int = alt;
spin_lock(&mbim->lock);
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE;
spin_unlock(&mbim->lock);
} else {
goto fail;
@@ -1387,7 +1389,7 @@
pr_info("SET DEVICE OFFLINE");
atomic_set(&mbim->online, 0);
- mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
mbim_clear_queues(mbim);
mbim_reset_function_queue(mbim);
@@ -1453,6 +1455,7 @@
mbim_union_desc.bSlaveInterface0 = status;
mbim->bam_port.cdev = cdev;
+ mbim->bam_port.func = &mbim->function;
status = -ENODEV;
@@ -1572,6 +1575,7 @@
{
struct f_mbim *mbim = func_to_mbim(f);
+ bam_data_destroy(mbim->port_num);
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
@@ -1655,12 +1659,13 @@
mbim->xport = USB_GADGET_XPORT_BAM2BAM;
} else {
/* For IPA we use limit of 16 */
- ntb_parameters.wNtbOutMaxDatagrams = 16;
+ mbim_ntb_parameters.wNtbOutMaxDatagrams = 16;
/* For IPA this is proven to give maximum throughput */
- ntb_parameters.dwNtbInMaxSize =
+ mbim_ntb_parameters.dwNtbInMaxSize =
cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
- ntb_parameters.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE_IPA);
- ntb_parameters.wNdpInDivisor = 1;
+ mbim_ntb_parameters.dwNtbOutMaxSize =
+ cpu_to_le32(MBIM_NTB_OUT_SIZE_IPA);
+ mbim_ntb_parameters.wNdpInDivisor = 1;
}
INIT_LIST_HEAD(&mbim->cpkt_req_q);
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0c0d58a..4586d80 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);
}
@@ -679,8 +696,8 @@
break;
}
- if (count > MTP_BULK_BUFFER_SIZE)
- xfer = MTP_BULK_BUFFER_SIZE;
+ if (count > mtp_tx_req_len)
+ xfer = mtp_tx_req_len;
else
xfer = count;
if (xfer && copy_from_user(req->buf, buf, xfer)) {
@@ -772,8 +789,8 @@
break;
}
- if (count > MTP_BULK_BUFFER_SIZE)
- xfer = MTP_BULK_BUFFER_SIZE;
+ if (count > mtp_tx_req_len)
+ xfer = mtp_tx_req_len;
else
xfer = count;
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index aab8ede..cdf86fd 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -24,6 +24,21 @@
#include "u_ether.h"
+#undef DBG
+#undef VDBG
+#undef ERROR
+#undef INFO
+
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
/*
* This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
* NCM is intended to be used with high-speed network attachments.
@@ -124,7 +139,7 @@
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
-static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
+static struct usb_interface_assoc_descriptor ncm_iad_desc = {
.bLength = sizeof ncm_iad_desc,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
@@ -138,7 +153,7 @@
/* interface descriptor: */
-static struct usb_interface_descriptor ncm_control_intf __initdata = {
+static struct usb_interface_descriptor ncm_control_intf = {
.bLength = sizeof ncm_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -150,7 +165,7 @@
/* .iInterface = DYNAMIC */
};
-static struct usb_cdc_header_desc ncm_header_desc __initdata = {
+static struct usb_cdc_header_desc ncm_header_desc = {
.bLength = sizeof ncm_header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
@@ -158,7 +173,7 @@
.bcdCDC = cpu_to_le16(0x0110),
};
-static struct usb_cdc_union_desc ncm_union_desc __initdata = {
+static struct usb_cdc_union_desc ncm_union_desc = {
.bLength = sizeof(ncm_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@@ -166,8 +181,8 @@
/* .bSlaveInterface0 = DYNAMIC */
};
-static struct usb_cdc_ether_desc ecm_desc __initdata = {
- .bLength = sizeof ecm_desc,
+static struct usb_cdc_ether_desc necm_desc = {
+ .bLength = sizeof necm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
@@ -181,7 +196,7 @@
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
-static struct usb_cdc_ncm_desc ncm_desc __initdata = {
+static struct usb_cdc_ncm_desc ncm_desc = {
.bLength = sizeof ncm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_NCM_TYPE,
@@ -193,7 +208,7 @@
/* the default data interface has no endpoints ... */
-static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_nop_intf = {
.bLength = sizeof ncm_data_nop_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -208,7 +223,7 @@
/* ... but the "real" data interface has two bulk endpoints */
-static struct usb_interface_descriptor ncm_data_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_intf = {
.bLength = sizeof ncm_data_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -223,7 +238,7 @@
/* full speed support: */
-static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -233,7 +248,7 @@
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
};
-static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -241,7 +256,7 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -249,13 +264,13 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_fs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
(struct usb_descriptor_header *) &ncm_header_desc,
(struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &necm_desc,
(struct usb_descriptor_header *) &ncm_desc,
(struct usb_descriptor_header *) &fs_ncm_notify_desc,
/* data interface, altsettings 0 and 1 */
@@ -268,7 +283,7 @@
/* high speed support: */
-static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -277,7 +292,7 @@
.wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
};
-static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -286,7 +301,7 @@
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -295,13 +310,13 @@
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_hs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
(struct usb_descriptor_header *) &ncm_header_desc,
(struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &necm_desc,
(struct usb_descriptor_header *) &ncm_desc,
(struct usb_descriptor_header *) &hs_ncm_notify_desc,
/* data interface, altsettings 0 and 1 */
@@ -316,13 +331,13 @@
#define STRING_CTRL_IDX 0
#define STRING_MAC_IDX 1
-#define STRING_DATA_IDX 2
+#define NCM_STRING_DATA_IDX 2
#define STRING_IAD_IDX 3
static struct usb_string ncm_string_defs[] = {
[STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)",
[STRING_MAC_IDX].s = NULL /* DYNAMIC */,
- [STRING_DATA_IDX].s = "CDC Network Data",
+ [NCM_STRING_DATA_IDX].s = "CDC Network Data",
[STRING_IAD_IDX].s = "CDC NCM",
{ } /* end of list */
};
@@ -1148,7 +1163,7 @@
/* ethernet function driver setup/binding */
-static int __init
+static int
ncm_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
@@ -1299,7 +1314,7 @@
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
{
struct f_ncm *ncm;
int status;
@@ -1321,7 +1336,7 @@
status = usb_string_id(c->cdev);
if (status < 0)
return status;
- ncm_string_defs[STRING_DATA_IDX].id = status;
+ ncm_string_defs[NCM_STRING_DATA_IDX].id = status;
ncm_data_nop_intf.iInterface = status;
ncm_data_intf.iInterface = status;
@@ -1330,7 +1345,7 @@
if (status < 0)
return status;
ncm_string_defs[STRING_MAC_IDX].id = status;
- ecm_desc.iMACAddress = status;
+ necm_desc.iMACAddress = status;
/* IAD */
status = usb_string_id(c->cdev);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 4f9cbf1..3db5b51 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -75,6 +75,7 @@
struct usb_request *notify_req;
u8 notify_state;
bool is_open;
+ struct data_port bam_port;
};
static struct ecm_ipa_params ipa_params;
@@ -111,8 +112,9 @@
#define ECM_QC_LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define ECM_QC_STATUS_BYTECOUNT 16 /* 8 byte header + data */
-/* currently only one std ecm instance is supported */
+/* Currently only one std ecm instance is supported - port index 0. */
#define ECM_QC_NO_PORTS 1
+#define ECM_QC_ACTIVE_PORT 0
/* interface descriptor: */
@@ -296,8 +298,6 @@
NULL,
};
-static struct data_port ecm_qc_bam_port;
-
static void ecm_qc_do_notify(struct f_ecm_qc *ecm)
{
struct usb_request *req = ecm->notify_req;
@@ -388,10 +388,10 @@
enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
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;
+ 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;
/* currently we use the first connection */
src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
@@ -402,7 +402,7 @@
pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
return ret;
}
- ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
+ ret = bam_data_connect(&dev->bam_port, 0, dev->xport,
src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n", ret);
@@ -421,7 +421,7 @@
{
pr_debug("dev:%p. Disconnect BAM.\n", dev);
- bam_data_disconnect(&ecm_qc_bam_port, 0);
+ bam_data_disconnect(&dev->bam_port, 0);
return 0;
}
@@ -656,6 +656,20 @@
}
}
+static void ecm_qc_suspend(struct usb_function *f)
+{
+ pr_debug("ecm suspended\n");
+
+ bam_data_suspend(ECM_QC_ACTIVE_PORT);
+}
+
+static void ecm_qc_resume(struct usb_function *f)
+{
+ pr_debug("ecm resumed\n");
+
+ bam_data_resume(ECM_QC_ACTIVE_PORT);
+}
+
/*-------------------------------------------------------------------------*/
/*
@@ -832,6 +846,7 @@
DBG(c->cdev, "ecm unbind\n");
+ bam_data_destroy(0);
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
@@ -939,6 +954,8 @@
ecm->port.func.get_alt = ecm_qc_get_alt;
ecm->port.func.setup = ecm_qc_setup;
ecm->port.func.disable = ecm_qc_disable;
+ ecm->port.func.suspend = ecm_qc_suspend;
+ ecm->port.func.resume = ecm_qc_resume;
status = usb_add_function(c, &ecm->port.func);
if (status) {
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 267cf53..c1ab552 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -725,14 +725,14 @@
*/
rndis->port.cdc_filter = 0;
+ if (rndis_qc_bam_connect(rndis))
+ goto fail;
+
DBG(cdev, "RNDIS RX/TX early activation ...\n");
net = gether_qc_connect_name(&rndis->port, "rndis0", false);
if (IS_ERR(net))
return PTR_ERR(net);
- if (rndis_qc_bam_connect(rndis))
- goto fail;
-
rndis_set_param_dev(rndis->config, net,
&rndis->port.cdc_filter);
} else
@@ -976,6 +976,8 @@
{
struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ pr_debug("rndis_qc_unbind: free");
+ bam_data_destroy(0);
rndis_deregister(rndis->config);
rndis_exit();
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 32d4011..7903764 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -66,10 +66,10 @@
* - MS-Windows drivers sometimes emit undocumented requests.
*/
-static bool rndis_multipacket_dl_disable;
-module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(rndis_multipacket_dl_disable,
- "Disable RNDIS Multi-packet support in DownLink");
+static unsigned int rndis_dl_max_pkt_per_xfer = 3;
+module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
+ "Maximum packets per transfer for DL aggregation");
static unsigned int rndis_ul_max_pkt_per_xfer = 3;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
@@ -488,7 +488,7 @@
__func__, buf->MaxTransferSize,
rndis->port.multi_pkt_xfer ? "enabled" :
"disabled");
- if (rndis_multipacket_dl_disable)
+ if (rndis_dl_max_pkt_per_xfer <= 1)
rndis->port.multi_pkt_xfer = 0;
}
// spin_unlock(&dev->lock);
@@ -952,6 +952,7 @@
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
+ rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index b71f903..9dd9978 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -778,6 +778,7 @@
unsigned long flags;
if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
+ usb_bam_reset_complete();
ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
if (ret) {
pr_err("%s: usb_bam_connect (src) failed: err:%d\n",
@@ -916,7 +917,7 @@
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_a2_reset();
+ ret = usb_bam_a2_reset(0);
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
goto reenable_eps;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index c638164..5c7e52f 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -145,69 +145,24 @@
struct bam_data_port *port = (struct bam_data_port *)param;
struct bam_data_ch_info *d;
int ret;
- bool reenable_eps = false;
d = &port->data_ch;
pr_debug("%s: reset by peer\n", __func__);
- /* Disable the relevant EPs if currently EPs are enabled */
- if (port->port_usb && port->port_usb->in &&
- port->port_usb->in->driver_data) {
- usb_ep_disable(port->port_usb->out);
- usb_ep_disable(port->port_usb->in);
-
- port->port_usb->in->driver_data = NULL;
- port->port_usb->out->driver_data = NULL;
- reenable_eps = true;
- }
-
/* Disable BAM */
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_a2_reset();
+ ret = usb_bam_a2_reset(0);
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
- goto reenable_eps;
+ return ret;
}
/* Enable BAM */
msm_hw_bam_disable(0);
-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",
- __func__, port->port_usb->in);
- return ret;
- }
- port->port_usb->in->driver_data = port;
-
- ret = usb_ep_enable(port->port_usb->out);
- if (ret) {
- pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
- __func__, port->port_usb->out);
- port->port_usb->in->driver_data = 0;
- return ret;
- }
- port->port_usb->out->driver_data = port;
-
- bam_data_start_endless_rx(port);
- bam_data_start_endless_tx(port);
- }
-
/* Unregister the peer reset callback */
usb_bam_register_peer_reset_cb(NULL, NULL);
@@ -244,6 +199,7 @@
int ret;
pr_debug("%s: Connect workqueue started", __func__);
+ usb_bam_reset_complete();
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
if (d->func_type == USB_FUNC_MBIM) {
@@ -504,6 +460,23 @@
return 0;
}
+int bam_data_destroy(unsigned int no_bam2bam_port)
+{
+ struct bam_data_ch_info *d;
+ struct bam_data_port *port;
+
+ port = bam2bam_data_ports[no_bam2bam_port];
+ d = &port->data_ch;
+
+ pr_debug("bam_data_destroy: Freeing ports\n");
+ bam2bam_data_port_free(no_bam2bam_port);
+ if (bam_data_wq)
+ destroy_workqueue(bam_data_wq);
+ bam_data_wq = NULL;
+
+ return 0;
+}
+
int bam_data_setup(unsigned int no_bam2bam_port)
{
int i;
@@ -516,6 +489,11 @@
return -EINVAL;
}
+ if (bam_data_wq) {
+ pr_debug("bam_data is already setup");
+ return 0;
+ }
+
bam_data_wq = alloc_workqueue("k_bam_data",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!bam_data_wq) {
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 5ce678d..61f653a 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -36,6 +36,8 @@
int bam_data_setup(unsigned int no_bam2bam_port);
+int bam_data_destroy(unsigned int no_bam2bam_port);
+
void bam_data_suspend(u8 port_num);
void bam_data_resume(u8 port_num);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index dbffa4e..9961d00 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -71,6 +71,7 @@
unsigned header_len;
unsigned int ul_max_pkts_per_xfer;
+ unsigned int dl_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
@@ -585,12 +586,12 @@
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
{
struct list_head *act;
struct usb_request *req;
- dev->tx_req_bufsize = (TX_SKB_HOLD_THRESHOLD *
+ dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer *
(dev->net->mtu
+ sizeof(struct ethhdr)
/* size of rndis_packet_msg_type */
@@ -602,7 +603,19 @@
if (!req->buf)
req->buf = kmalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
+ if (!req->buf)
+ goto free_buf;
}
+ return 0;
+
+free_buf:
+ /* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+ dev->tx_req_bufsize = 0;
+ list_for_each(act, &dev->tx_reqs) {
+ req = container_of(act, struct usb_request, list);
+ kfree(req->buf);
+ }
+ return -ENOMEM;
}
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -634,8 +647,11 @@
}
/* Allocate memory for tx_reqs to support multi packet transfer */
- if (multi_pkt_xfer && !dev->tx_req_bufsize)
- alloc_tx_buffer(dev);
+ if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+ retval = alloc_tx_buffer(dev);
+ if (retval < 0)
+ return -ENOMEM;
+ }
/* apply outgoing CDC or RNDIS filters */
if (!is_promisc(cdc_filter)) {
@@ -704,7 +720,7 @@
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
- if (dev->tx_skb_hold_count < TX_SKB_HOLD_THRESHOLD) {
+ if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -1082,6 +1098,7 @@
dev->unwrap = link->unwrap;
dev->wrap = link->wrap;
dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
+ dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer;
spin_lock(&dev->lock);
dev->tx_skb_hold_count = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 7040ab0..05984d8 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -55,8 +55,7 @@
u32 fixed_in_len;
unsigned ul_max_pkts_per_xfer;
-/* Max number of SKB packets to be used to create Multi Packet RNDIS */
-#define TX_SKB_HOLD_THRESHOLD 3
+ unsigned dl_max_pkts_per_xfer;
bool multi_pkt_xfer;
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index caea4ef..5767ba3 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -44,6 +44,7 @@
char *name;
unsigned long flags;
wait_queue_head_t wait;
+ wait_queue_head_t smd_wait_q;
unsigned dtr;
struct list_head tx_q;
@@ -111,8 +112,8 @@
{
struct smd_ch_info *c = container_of(w, struct smd_ch_info, read_w);
struct rmnet_ctrl_port *port = c->port;
- int sz;
- size_t len;
+ int sz, total_received, read_avail;
+ int len;
void *buf;
unsigned long flags;
@@ -122,22 +123,47 @@
if (sz <= 0)
break;
- if (smd_read_avail(c->ch) < sz)
- break;
-
spin_unlock_irqrestore(&port->port_lock, flags);
buf = kmalloc(sz, GFP_KERNEL);
if (!buf)
return;
- len = smd_read(c->ch, buf, sz);
+ total_received = 0;
+ while (total_received < sz) {
+ wait_event(c->smd_wait_q,
+ ((read_avail = smd_read_avail(c->ch)) ||
+ (c->ch == 0)));
+
+ if (read_avail < 0 || c->ch == 0) {
+ pr_err("%s:smd read_avail failure:%d or channel closed ch=%p",
+ __func__, read_avail, c->ch);
+ kfree(buf);
+ return;
+ }
+
+ if (read_avail + total_received > sz) {
+ pr_err("%s: SMD sending incorrect pkt\n",
+ __func__);
+ kfree(buf);
+ return;
+ }
+
+ len = smd_read(c->ch, buf + total_received, read_avail);
+ if (len <= 0) {
+ pr_err("%s: smd read failure %d\n",
+ __func__, len);
+ kfree(buf);
+ return;
+ }
+ total_received += len;
+ }
/* send it to USB here */
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb && port->port_usb->send_cpkt_response) {
port->port_usb->send_cpkt_response(port->port_usb,
- buf, len);
+ buf, sz);
c->to_host++;
}
kfree(buf);
@@ -304,7 +330,7 @@
switch (event) {
case SMD_EVENT_DATA:
- if (smd_read_avail(c->ch))
+ if (smd_read_avail(c->ch) && !waitqueue_active(&c->smd_wait_q))
queue_work(grmnet_ctrl_wq, &c->read_w);
if (smd_write_avail(c->ch))
queue_work(grmnet_ctrl_wq, &c->write_w);
@@ -334,6 +360,7 @@
break;
}
+ wake_up(&c->smd_wait_q);
}
/*------------------------------------------------------------ */
@@ -579,6 +606,7 @@
[portno % MAX_CTRL_PER_CLIENT];
c->port = port;
init_waitqueue_head(&c->wait);
+ init_waitqueue_head(&c->smd_wait_q);
INIT_LIST_HEAD(&c->tx_q);
INIT_WORK(&c->read_w, grmnet_ctrl_smd_read_w);
INIT_WORK(&c->write_w, grmnet_ctrl_smd_write_w);
@@ -604,6 +632,11 @@
pr_debug("%s: requested ports:%d\n", __func__, count);
+ if (client_num >= NR_CTRL_CLIENTS) {
+ pr_err("%s: Invalid client:%d\n", __func__, client_num);
+ return -EINVAL;
+ }
+
if (!count || count > MAX_CTRL_PER_CLIENT) {
pr_err("%s: Invalid num of ports count:%d\n",
__func__, count);
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index a0cdde2..52b707e 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -232,7 +232,7 @@
{
unsigned avail;
char *packet;
- unsigned size = req->actual;
+ unsigned size;
unsigned n;
int ret = 0;
@@ -271,6 +271,7 @@
return -ENODEV;
}
+ size = req->actual;
packet = req->buf;
n = port->n_read;
if (n) {
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 0ea9778..f16a0b6 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1062,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;
@@ -1092,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);
@@ -1882,6 +1889,8 @@
"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;
}
@@ -2121,7 +2130,8 @@
if (mehci->enable_hbm)
hbm_init(hcd, pdata->disable_park_mode);
- msm_bam_set_hsic_host_dev(&pdev->dev);
+ if (pdata && pdata->consider_ipa_handshake)
+ msm_bam_set_hsic_host_dev(&pdev->dev);
return 0;
@@ -2146,7 +2156,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 (pdata && pdata->consider_ipa_handshake)
+ 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)
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 521ace0..c2e8943 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -103,6 +103,7 @@
.bus_resume = ehci_bus_resume,
};
+static u64 msm_ehci_dma_mask = DMA_BIT_MASK(64);
static int ehci_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -111,6 +112,11 @@
dev_dbg(&pdev->dev, "ehci_msm proble\n");
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &msm_ehci_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 44a7aee..5055dcf 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1259,7 +1259,14 @@
/* Set max current limit */
if (power_supply_set_current_limit(psy, 0))
goto psy_error;
+ } else {
+ if (power_supply_set_online(psy, true))
+ goto psy_error;
+ /* Current has changed (100/2 --> 500) */
+ if (power_supply_set_current_limit(psy, 1000*mA))
+ goto psy_error;
}
+
power_supply_changed(psy);
return 0;
@@ -1498,7 +1505,7 @@
vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
if (IS_ERR(vbus_otg)) {
pr_err("Unable to get vbus_otg\n");
- return -ENODEV;
+ return PTR_ERR(vbus_otg);
}
}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 887dde7..96f0f8c 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -35,8 +35,7 @@
struct completion dma_comp;
int irq_enabled;
spinlock_t irq_lock;
- spinlock_t mdp_lock;
- int mdp_busy;
+
int irq_no;
unsigned char *dsi_base;
struct device dis_dev;
@@ -57,7 +56,6 @@
init_completion(&dsi_host_private->dma_comp);
spin_lock_init(&dsi_host_private->irq_lock);
- spin_lock_init(&dsi_host_private->mdp_lock);
return 0;
}
@@ -140,14 +138,10 @@
unsigned long flags;
spin_lock_irqsave(&dsi_host_private->irq_lock, flags);
- if (dsi_host_private->irq_enabled) {
- pr_debug("%s: IRQ aleady enabled\n", __func__);
- spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags);
- return;
- }
+ dsi_host_private->irq_enabled++;
+ if (dsi_host_private->irq_enabled == 1)
+ enable_irq(dsi_host_private->irq_no);
- enable_irq(dsi_host_private->irq_no);
- dsi_host_private->irq_enabled = 1;
spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags);
}
@@ -156,26 +150,19 @@
unsigned long flags;
spin_lock_irqsave(&dsi_host_private->irq_lock, flags);
- if (dsi_host_private->irq_enabled == 0) {
- pr_debug("%s: IRQ already disabled\n", __func__);
- spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags);
- return;
- }
- disable_irq(dsi_host_private->irq_no);
- dsi_host_private->irq_enabled = 0;
+ dsi_host_private->irq_enabled--;
+ if (dsi_host_private->irq_enabled == 0)
+ disable_irq(dsi_host_private->irq_no);
+
spin_unlock_irqrestore(&dsi_host_private->irq_lock, flags);
}
void msm_dsi_disable_irq_nosync(void)
{
spin_lock(&dsi_host_private->irq_lock);
- if (dsi_host_private->irq_enabled == 0) {
- pr_debug("%s: IRQ cannot be disabled\n", __func__);
- spin_unlock(&dsi_host_private->irq_lock);
- return;
- }
- disable_irq_nosync(dsi_host_private->irq_no);
- dsi_host_private->irq_enabled = 0;
+ dsi_host_private->irq_enabled--;
+ if (dsi_host_private->irq_enabled == 0)
+ disable_irq_nosync(dsi_host_private->irq_no);
spin_unlock(&dsi_host_private->irq_lock);
}
@@ -192,13 +179,6 @@
if (isr & DSI_INTR_CMD_DMA_DONE)
complete(&dsi_host_private->dma_comp);
- if (isr & DSI_INTR_CMD_MDP_DONE) {
- spin_lock(&dsi_host_private->mdp_lock);
- dsi_host_private->mdp_busy = false;
- msm_dsi_disable_irq_nosync();
- spin_unlock(&dsi_host_private->mdp_lock);
- }
-
return IRQ_HANDLED;
}
@@ -448,16 +428,6 @@
wmb();
}
-void msm_dsi_cmd_mdp_start(void)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&dsi_host_private->mdp_lock, flag);
- msm_dsi_enable_irq();
- dsi_host_private->mdp_busy = true;
- spin_unlock_irqrestore(&dsi_host_private->mdp_lock, flag);
-}
-
int msm_dsi_cmd_reg_tx(u32 data)
{
unsigned char *ctrl_base = dsi_host_private->dsi_base;
@@ -551,7 +521,6 @@
struct dsi_cmd_desc *cm;
u32 dsi_ctrl, ctrl;
int i, video_mode;
- unsigned long flag;
unsigned char *ctrl_base = dsi_host_private->dsi_base;
/* turn on cmd mode
@@ -566,13 +535,9 @@
MIPI_OUTP(ctrl_base + DSI_CTRL, ctrl);
}
- spin_lock_irqsave(&dsi_host_private->mdp_lock, flag);
msm_dsi_enable_irq();
- dsi_host_private->mdp_busy = true;
- spin_unlock_irqrestore(&dsi_host_private->mdp_lock, flag);
cm = cmds;
- dsi_buf_init(tp);
for (i = 0; i < cnt; i++) {
dsi_buf_init(tp);
dsi_cmd_dma_add(tp, cm);
@@ -582,10 +547,7 @@
cm++;
}
- spin_lock_irqsave(&dsi_host_private->mdp_lock, flag);
- dsi_host_private->mdp_busy = false;
msm_dsi_disable_irq();
- spin_unlock_irqrestore(&dsi_host_private->mdp_lock, flag);
if (video_mode)
MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl);
@@ -617,7 +579,6 @@
struct dsi_cmd_desc *cmds, int rlen)
{
int cnt, len, diff, pkt_size;
- unsigned long flag;
char cmd;
if (pdata->panel_info.mipi.no_max_pkt_size)
@@ -645,10 +606,7 @@
cnt = len + 6; /* 4 bytes header + 2 bytes crc */
}
- spin_lock_irqsave(&dsi_host_private->mdp_lock, flag);
msm_dsi_enable_irq();
- dsi_host_private->mdp_busy = true;
- spin_unlock_irqrestore(&dsi_host_private->mdp_lock, flag);
if (!pdata->panel_info.mipi.no_max_pkt_size) {
/* packet size need to be set at every read */
@@ -681,10 +639,7 @@
msm_dsi_cmd_dma_rx(rp, cnt);
- spin_lock_irqsave(&dsi_host_private->mdp_lock, flag);
- dsi_host_private->mdp_busy = false;
msm_dsi_disable_irq();
- spin_unlock_irqrestore(&dsi_host_private->mdp_lock, flag);
if (pdata->panel_info.mipi.no_max_pkt_size) {
/*
@@ -890,7 +845,7 @@
msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
msm_dsi_clk_disable();
msm_dsi_unprepare_clocks();
-
+ msm_dsi_phy_off(dsi_host_private->dsi_base);
msm_dsi_ahb_ctrl(0);
ret = msm_dsi_regulator_disable();
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index 93f2c76..cbdd241 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -435,15 +435,7 @@
wmb();
}
-void msm_dsi_phy_enable(unsigned char *ctrl_base, int on)
+void msm_dsi_phy_off(unsigned char *ctrl_base)
{
- if (on) {
- MIPI_OUTP(ctrl_base + DSI_DSIPHY_PLL_CTRL_5, 0x050);
- } else {
- MIPI_OUTP(ctrl_base + DSI_DSIPHY_PLL_CTRL_5, 0x05f);
- MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, 0x02);
- MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x00);
- MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_1, 0x7f);
- MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0);
- }
+ MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x00);
}
diff --git a/drivers/video/msm/mdss/dsi_io_v2.h b/drivers/video/msm/mdss/dsi_io_v2.h
index 285bf30..a7d43a0 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.h
+++ b/drivers/video/msm/mdss/dsi_io_v2.h
@@ -51,4 +51,5 @@
void msm_dsi_phy_sw_reset(unsigned char *ctrl_base);
+void msm_dsi_phy_off(unsigned char *ctrl_base);
#endif /* DSI_IO_V2_H */
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..e5b6603 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -94,7 +94,7 @@
static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = {
.usecase = mdp_bus_ppp_usecases,
.num_usecases = ARRAY_SIZE(mdp_bus_ppp_usecases),
- .name = "mdp3",
+ .name = "mdp3_ppp",
};
struct mdp3_bus_handle_map mdp3_bus_handle[MDP3_BUS_HANDLE_MAX] = {
@@ -206,18 +206,7 @@
unsigned long flag;
spin_lock_irqsave(&mdp3_res->irq_lock, flag);
- if (mdp3_res->irq_ref_count[type] <= 0) {
- pr_debug("interrupt %d not enabled\n", type);
- spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
- return;
- }
- mdp3_res->irq_ref_count[type] -= 1;
- if (mdp3_res->irq_ref_count[type] == 0) {
- mdp3_res->irq_mask &= ~BIT(type);
- MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask);
- if (!mdp3_res->irq_mask)
- disable_irq(mdp3_res->irq);
- }
+ mdp3_irq_disable_nosync(type);
spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
}
@@ -290,12 +279,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;
}
}
@@ -389,7 +382,8 @@
-int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate)
+int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate,
+ int client)
{
int ret = 0;
unsigned long rounded_rate;
@@ -403,6 +397,19 @@
mutex_unlock(&mdp3_res->res_mutex);
return -EINVAL;
}
+ if (clk_type == MDP3_CLK_CORE) {
+ if (client == MDP3_CLIENT_DMA_P) {
+ mdp3_res->dma_core_clk_request = rounded_rate;
+ } else if (client == MDP3_CLIENT_PPP) {
+ mdp3_res->ppp_core_clk_request = rounded_rate;
+ } else {
+ pr_err("unrecognized client=%d\n", client);
+ mutex_unlock(&mdp3_res->res_mutex);
+ return -EINVAL;
+ }
+ rounded_rate = max(mdp3_res->dma_core_clk_request,
+ mdp3_res->ppp_core_clk_request);
+ }
if (rounded_rate != clk_get_rate(clk)) {
ret = clk_set_rate(clk, rounded_rate);
if (ret)
@@ -484,11 +491,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 +535,7 @@
return ret;
}
disable_irq(mdp3_res->irq);
+ mdp3_res->irq_registered = true;
return 0;
}
@@ -556,7 +573,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 +613,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 +644,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 +677,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;
@@ -725,11 +762,6 @@
if (rc)
return rc;
- rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_DMA_0);
- if (rc) {
- pr_err("fail to attach DMA-P context 0\n");
- return rc;
- }
mdp3_res->bus_handle = mdp3_bus_handle;
rc = mdp3_bus_scale_register();
if (rc) {
@@ -742,6 +774,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 +894,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;
}
@@ -876,19 +926,31 @@
return ret;
}
-int mdp3_ppp_iommu_attach(void)
+int mdp3_iommu_enable(int client)
{
int rc;
- rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_0);
- rc |= mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_1);
+
+ if (client == MDP3_CLIENT_DMA_P) {
+ rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_DMA_0);
+ } else {
+ rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_0);
+ rc |= mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_1);
+ }
+
return rc;
}
-int mdp3_ppp_iommu_dettach(void)
+int mdp3_iommu_disable(int client)
{
int rc;
- rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_0);
- rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_1);
+
+ if (client == MDP3_CLIENT_DMA_P) {
+ rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_DMA_0);
+ } else {
+ rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_0);
+ rc |= mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_1);
+ }
+
return rc;
}
@@ -896,7 +958,7 @@
{
int rc;
rc = mdp3_ctrl_init(mfd);
- rc |= mdp3_ppp_res_init();
+ rc |= mdp3_ppp_res_init(mfd);
return rc;
}
@@ -1002,6 +1064,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..1afae01 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;
};
@@ -139,13 +141,13 @@
void mdp3_irq_disable(int type);
void mdp3_irq_disable_nosync(int type);
int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb);
-int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate);
+int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
int mdp3_clk_enable(int enable);
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data);
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
-int mdp3_ppp_iommu_attach(void);
-int mdp3_ppp_iommu_dettach(void);
+int mdp3_iommu_enable(int client);
+int mdp3_iommu_disable(int client);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index b5134a7..734756c 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -29,6 +29,7 @@
#define VSYNC_PERIOD 16
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
+static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
{
@@ -129,52 +130,41 @@
return 0;
}
-static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+static int mdp3_ctrl_async_blit_req(struct msm_fb_data_type *mfd,
+ void __user *p)
{
- const int MAX_LIST_WINDOW = 16;
- struct mdp_blit_req req_list[MAX_LIST_WINDOW];
- struct mdp_blit_req_list req_list_header;
- int rc, count, i, req_list_count;
+ struct mdp_async_blit_req_list req_list_header;
+ int rc, count;
+ void __user *p_req;
if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
return -EFAULT;
- p += sizeof(req_list_header);
+ p_req = p + sizeof(req_list_header);
count = req_list_header.count;
if (count < 0 || count >= MAX_BLIT_REQ)
return -EINVAL;
- while (count > 0) {
- /*
- * Access the requests through a narrow window to decrease copy
- * overhead and make larger requests accessible to the
- * coherency management code.
- * NOTE: The window size is intended to be larger than the
- * typical request size, but not require more than 2
- * kbytes of stack storage.
- */
- req_list_count = count;
- if (req_list_count > MAX_LIST_WINDOW)
- req_list_count = MAX_LIST_WINDOW;
- if (copy_from_user(&req_list, p,
- sizeof(struct mdp_blit_req)*req_list_count))
- return -EFAULT;
- /*
- * Do the blit DMA, if required -- returning early only if
- * there is a failure.
- */
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags & MDP_NO_BLIT)) {
- /* Do the actual blit. */
- rc = mdp3_ppp_start_blit(mfd, &(req_list[i]));
- if (rc)
- return rc;
- }
- }
+ rc = mdp3_ppp_parse_req(p_req, &req_list_header, 1);
+ if (!rc)
+ rc = copy_to_user(p, &req_list_header, sizeof(req_list_header));
+ return rc;
+}
- /* Go to next window of requests. */
- count -= req_list_count;
- p += sizeof(struct mdp_blit_req)*req_list_count;
- }
- return 0;
+static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+{
+ struct mdp_async_blit_req_list req_list_header;
+ int rc, count;
+ void __user *p_req;
+
+ if (copy_from_user(&(req_list_header.count), p,
+ sizeof(struct mdp_blit_req_list)))
+ return -EFAULT;
+ p_req = p + sizeof(struct mdp_blit_req_list);
+ count = req_list_header.count;
+ if (count < 0 || count >= MAX_BLIT_REQ)
+ return -EINVAL;
+ req_list_header.sync.acq_fen_fd_cnt = 0;
+ rc = mdp3_ppp_parse_req(p_req, &req_list_header, 0);
+ return rc;
}
static ssize_t mdp3_vsync_show_event(struct device *dev,
@@ -192,13 +182,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);
@@ -242,8 +228,10 @@
int rc = 0;
if (status) {
- mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE);
- mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE);
+ mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE,
+ MDP3_CLIENT_DMA_P);
+ mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
+ MDP3_CLIENT_DMA_P);
rc = mdp3_clk_enable(true);
if (rc)
@@ -410,10 +398,18 @@
goto on_error;
}
+ rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
+ if (rc) {
+ pr_err("fail to attach MDP DMA SMMU\n");
+ goto on_error;
+ }
+
/* request bus bandwidth before DSI DMA traffic */
rc = mdp3_ctrl_res_req_bus(mfd, 1);
- if (rc)
+ if (rc) {
pr_err("fail to request bus resource\n");
+ goto on_error;
+ }
panel = mdp3_session->panel;
if (panel->event_handler)
@@ -443,9 +439,6 @@
rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
if (rc) {
pr_err("display interface init failed\n");
-
-
-
goto on_error;
}
@@ -505,10 +498,16 @@
rc = mdp3_ctrl_res_req_clk(mfd, 0);
if (rc)
pr_err("mdp clock resource release failed\n");
+
+ rc = mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
+ if (rc)
+ pr_err("fail to dettach MDP DMA SMMU\n");
+
off_error:
mdp3_session->status = 0;
-
mutex_unlock(&mdp3_session->lock);
+ if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
+ mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
return 0;
}
@@ -747,6 +746,9 @@
rc = -EFAULT;
}
break;
+ case MSMFB_ASYNC_BLIT:
+ rc = mdp3_ctrl_async_blit_req(mfd, argp);
+ break;
case MSMFB_BLIT:
rc = mdp3_ctrl_blit_req(mfd, argp);
break;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index fa2e9eb..94ad9be 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -28,8 +28,6 @@
pr_debug("mdp3_vsync_intr_handler\n");
spin_lock(&dma->dma_lock);
vsync_client = dma->vsync_client;
- if (!vsync_client.handler)
- dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_VSYNC;
complete(&dma->vsync_comp);
spin_unlock(&dma->dma_lock);
if (vsync_client.handler)
@@ -43,10 +41,6 @@
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
pr_debug("mdp3_dma_done_intr_handler\n");
- spin_lock(&dma->dma_lock);
- dma->busy = false;
- dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
- spin_unlock(&dma->dma_lock);
complete(&dma->dma_comp);
mdp3_irq_disable_nosync(type);
}
@@ -54,19 +48,9 @@
void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type)
{
int irq_bit;
- unsigned long flag;
pr_debug("mdp3_dma_callback_enable type=%d\n", type);
- spin_lock_irqsave(&dma->dma_lock, flag);
- if (dma->cb_type & type) {
- spin_unlock_irqrestore(&dma->dma_lock, flag);
- return;
- } else {
- dma->cb_type |= type;
- spin_unlock_irqrestore(&dma->dma_lock, flag);
- }
-
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) {
if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC)
@@ -92,19 +76,9 @@
void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type)
{
int irq_bit;
- unsigned long flag;
pr_debug("mdp3_dma_callback_disable type=%d\n", type);
- spin_lock_irqsave(&dma->dma_lock, flag);
- if ((dma->cb_type & type) == 0) {
- spin_unlock_irqrestore(&dma->dma_lock, flag);
- return;
- } else {
- dma->cb_type &= ~type;
- spin_unlock_irqrestore(&dma->dma_lock, flag);
- }
-
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) {
if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC)
@@ -443,7 +417,6 @@
static int mdp3_dmap_update(struct mdp3_dma *dma, void *buf)
{
- int wait_for_dma_done = 0;
unsigned long flag;
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
@@ -451,22 +424,15 @@
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
- spin_lock_irqsave(&dma->dma_lock, flag);
- if (dma->busy)
- wait_for_dma_done = 1;
- spin_unlock_irqrestore(&dma->dma_lock, flag);
-
- if (wait_for_dma_done)
- wait_for_completion_killable(&dma->dma_comp);
+ wait_for_completion_killable(&dma->dma_comp);
}
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
dma->source_config.buf = buf;
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 1);
- dma->busy = true;
- }
+
wmb();
init_completion(&dma->vsync_comp);
spin_unlock_irqrestore(&dma->dma_lock, flag);
@@ -480,28 +446,19 @@
static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf)
{
- int wait_for_dma_done = 0;
unsigned long flag;
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
- spin_lock_irqsave(&dma->dma_lock, flag);
- if (dma->busy)
- wait_for_dma_done = 1;
- spin_unlock_irqrestore(&dma->dma_lock, flag);
-
- if (wait_for_dma_done)
- wait_for_completion_killable(&dma->dma_comp);
+ wait_for_completion_killable(&dma->dma_comp);
}
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_ADDR, (u32)buf);
dma->source_config.buf = buf;
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
MDP3_REG_WRITE(MDP3_REG_DMA_S_START, 1);
- dma->busy = true;
- }
wmb();
init_completion(&dma->vsync_comp);
spin_unlock_irqrestore(&dma->dma_lock, flag);
@@ -613,7 +570,6 @@
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
MDP3_REG_WRITE(dma_start_offset, 1);
- dma->busy = true;
}
intf->start(intf);
@@ -653,7 +609,6 @@
mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_VSYNC |
MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
- dma->busy = false;
return ret;
}
@@ -666,8 +621,6 @@
pr_debug("mdp3_dma_init\n");
switch (dma->dma_sel) {
case MDP3_DMA_P:
- dma->busy = 0;
-
ret = mdp3_dmap_config(dma, source_config, output_config);
if (ret < 0)
return ret;
@@ -687,7 +640,6 @@
dma->stop = mdp3_dma_stop;
break;
case MDP3_DMA_S:
- dma->busy = 0;
ret = mdp3_dmas_config(dma, source_config, output_config);
if (ret < 0)
return ret;
@@ -715,7 +667,6 @@
spin_lock_init(&dma->dma_lock);
init_completion(&dma->vsync_comp);
init_completion(&dma->dma_comp);
- dma->cb_type = 0;
dma->vsync_client.handler = NULL;
dma->vsync_client.arg = NULL;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index cef749b..f86bea9 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -226,13 +226,11 @@
u32 capability;
int in_use;
int available;
- int busy;
spinlock_t dma_lock;
struct completion vsync_comp;
struct completion dma_comp;
struct mdp3_vsync_notification vsync_client;
- u32 cb_type;
struct mdp3_dma_output_config output_config;
struct mdp3_dma_source source_config;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 7164086..af316d3 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -20,6 +20,8 @@
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/mutex.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
#include "linux/proc_fs.h"
#include "mdss_fb.h"
@@ -28,6 +30,10 @@
#include "mdp3.h"
#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+#define MDP_BLIT_CLK_RATE 200000000
+#define MDP_PPP_MAX_BPP 4
+#define MDP_PPP_DYNAMIC_FACTOR 3
+#define MDP_PPP_MAX_READ_WRITE 3
static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
[MDP_RGB_565] = true,
@@ -47,11 +53,45 @@
[MDP_Y_CRCB_H2V1] = true,
};
+#define MAX_LIST_WINDOW 16
+#define MDP3_PPP_MAX_LIST_REQ 8
+
+struct blit_req_list {
+ int count;
+ struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+ struct mdp3_img_data src_data[MAX_LIST_WINDOW];
+ struct mdp3_img_data dst_data[MAX_LIST_WINDOW];
+ struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+ u32 acq_fen_cnt;
+ int cur_rel_fen_fd;
+ struct sync_pt *cur_rel_sync_pt;
+ struct sync_fence *cur_rel_fence;
+ struct sync_fence *last_rel_fence;
+};
+
+struct blit_req_queue {
+ struct blit_req_list req[MDP3_PPP_MAX_LIST_REQ];
+ int count;
+ int push_idx;
+ int pop_idx;
+};
+
struct ppp_status {
int busy;
+ bool wait_for_pop;
spinlock_t ppp_lock;
struct completion ppp_comp;
- struct mutex config_mutex;
+ struct completion pop_q_comp;
+ struct mutex req_mutex; /* Protect request queue */
+ struct mutex config_ppp_mutex; /* Only one client configure register */
+ struct msm_fb_data_type *mfd;
+
+ struct work_struct blit_work;
+ struct blit_req_queue req_q;
+
+ struct sw_sync_timeline *timeline;
+ int timeline_value;
+
};
static struct ppp_status *ppp_stat;
@@ -295,24 +335,22 @@
mdp3_ppp_pipe_wait();
}
-int mdp3_ppp_turnon(struct ppp_blit_op *blit_op, int on_off)
+int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
{
- unsigned long clk_rate = 0, dst_rate = 0, src_rate = 0;
- int ab = 0;
- int ib = 0;
- if (on_off) {
- dst_rate = blit_op->dst.roi.width * blit_op->dst.roi.height;
- src_rate = blit_op->src.roi.width * blit_op->src.roi.height;
- clk_rate = max(dst_rate, src_rate);
- clk_rate = clk_rate * 36 * 12;
+ struct mdss_panel_info *panel_info = mfd->panel_info;
+ int ab = 0, ib = 0;
+ int rate = 0;
- ab = blit_op->dst.roi.width * blit_op->dst.roi.height *
- ppp_bpp(blit_op->dst.color_fmt) * 2 +
- blit_op->src.roi.width * blit_op->src.roi.height *
- ppp_bpp(blit_op->src.color_fmt);
- ab = ab * 120;
+ if (on_off) {
+ rate = MDP_BLIT_CLK_RATE;
+ ab = panel_info->xres * panel_info->yres *
+ panel_info->mipi.frame_rate *
+ MDP_PPP_MAX_BPP *
+ MDP_PPP_DYNAMIC_FACTOR *
+ MDP_PPP_MAX_READ_WRITE;
ib = (ab * 3) / 2;
}
+ mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
mdp3_clk_enable(on_off);
mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
return 0;
@@ -322,10 +360,8 @@
{
/* Wait for the pipe to clear */
do { } while (mdp3_ppp_pipe_wait() <= 0);
- mutex_lock(&ppp_stat->config_mutex);
config_ppp_op_mode(blit_op);
mdp3_ppp_kickoff();
- mutex_unlock(&ppp_stat->config_mutex);
}
static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
@@ -504,7 +540,7 @@
}
}
-static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd,
+static int mdp3_ppp_blit(struct msm_fb_data_type *mfd,
struct mdp_blit_req *req, struct mdp3_img_data *src_data,
struct mdp3_img_data *dst_data)
{
@@ -524,8 +560,6 @@
mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
- mdp3_ppp_turnon(&blit_op, 1);
-
if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
(req->src.format == MDP_ARGB_8888) ||
(req->src.format == MDP_BGRA_8888) ||
@@ -536,41 +570,13 @@
mdp3_start_ppp(&blit_op);
}
- /* MDP cmd block disable */
- mdp3_ppp_turnon(&blit_op, 0);
-
return 0;
}
-static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req)
-{
- struct mdp3_img_data src_data;
- struct mdp3_img_data dst_data;
- int rc;
- mdp3_ppp_iommu_attach();
-
- mdp3_ppp_get_img(&req->src, req, &src_data);
- if (src_data.len == 0) {
- pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
- return -EINVAL;
- }
-
- mdp3_ppp_get_img(&req->dst, req, &dst_data);
- if (dst_data.len == 0) {
- mdp3_put_img(&src_data);
- pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
- return -EINVAL;
- }
-
- rc = mdp3_ppp_blit_addr(mfd, req, &src_data, &dst_data);
- mdp3_put_img(&src_data);
- mdp3_put_img(&dst_data);
- mdp3_ppp_iommu_dettach();
- return rc;
-}
-
static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd,
- struct mdp_blit_req *req, unsigned int remainder)
+ struct mdp_blit_req *req, unsigned int remainder,
+ struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
{
int ret;
struct mdp_blit_req splitreq;
@@ -669,7 +675,7 @@
}
/* No need to split in height */
- ret = mdp3_ppp_blit(mfd, &splitreq);
+ ret = mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data);
if (ret)
return ret;
@@ -698,11 +704,13 @@
}
/* No need to split in height ... just width */
- return mdp3_ppp_blit(mfd, &splitreq);
+ return mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data);
}
int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
- struct mdp_blit_req *req)
+ struct mdp_blit_req *req,
+ struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
{
int ret;
unsigned int remainder = 0, is_bpp_4 = 0;
@@ -742,19 +750,316 @@
is_bpp_4 = (ret == 4) ? 1 : 0;
if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
- ret = mdp3_ppp_blit_workaround(mfd, req, remainder);
+ ret = mdp3_ppp_blit_workaround(mfd, req, remainder,
+ src_data, dst_data);
else
- ret = mdp3_ppp_blit(mfd, req);
+ ret = mdp3_ppp_blit(mfd, req, src_data, dst_data);
+ mdp3_put_img(src_data);
+ mdp3_put_img(dst_data);
return ret;
}
-int mdp3_ppp_res_init(void)
+void mdp3_ppp_wait_for_fence(struct blit_req_list *req)
{
- ppp_stat = kmalloc(sizeof(struct ppp_status), GFP_KERNEL);
+ int i, ret = 0;
+ /* buf sync */
+ for (i = 0; i < req->acq_fen_cnt; i++) {
+ ret = sync_fence_wait(req->acq_fen[i],
+ WAIT_FENCE_FINAL_TIMEOUT);
+ if (ret < 0) {
+ pr_err("%s: sync_fence_wait failed! ret = %x\n",
+ __func__, ret);
+ break;
+ }
+ sync_fence_put(req->acq_fen[i]);
+ }
+
+ if (ret < 0) {
+ while (i < req->acq_fen_cnt) {
+ sync_fence_put(req->acq_fen[i]);
+ i++;
+ }
+ }
+ req->acq_fen_cnt = 0;
+}
+
+void mdp3_ppp_signal_timeline(struct blit_req_list *req)
+{
+ sw_sync_timeline_inc(ppp_stat->timeline, 1);
+ req->last_rel_fence = req->cur_rel_fence;
+ req->cur_rel_fence = 0;
+}
+
+
+static void mdp3_ppp_deinit_buf_sync(struct blit_req_list *req)
+{
+ int i;
+
+ put_unused_fd(req->cur_rel_fen_fd);
+ sync_fence_put(req->cur_rel_fence);
+ req->cur_rel_fence = NULL;
+ req->cur_rel_fen_fd = 0;
+ ppp_stat->timeline_value--;
+ for (i = 0; i < req->acq_fen_cnt; i++)
+ sync_fence_put(req->acq_fen[i]);
+ req->acq_fen_cnt = 0;
+}
+
+static int mdp3_ppp_handle_buf_sync(struct blit_req_list *req,
+ struct mdp_buf_sync *buf_sync)
+{
+ int i, fence_cnt = 0, ret = 0;
+ int acq_fen_fd[MDP_MAX_FENCE_FD];
+ struct sync_fence *fence;
+
+ if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+ (ppp_stat->timeline == NULL))
+ return -EINVAL;
+
+ if (buf_sync->acq_fen_fd_cnt)
+ ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
+ buf_sync->acq_fen_fd_cnt * sizeof(int));
+ if (ret) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+ return ret;
+ }
+ for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
+ fence = sync_fence_fdget(acq_fen_fd[i]);
+ if (fence == NULL) {
+ pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+ acq_fen_fd[i]);
+ ret = -EINVAL;
+ break;
+ }
+ req->acq_fen[i] = fence;
+ }
+ fence_cnt = i;
+ if (ret)
+ goto buf_sync_err_1;
+ req->acq_fen_cnt = fence_cnt;
+ if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+ mdp3_ppp_wait_for_fence(req);
+
+ req->cur_rel_sync_pt = sw_sync_pt_create(ppp_stat->timeline,
+ ppp_stat->timeline_value++);
+ if (req->cur_rel_sync_pt == NULL) {
+ pr_err("%s: cannot create sync point\n", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_2;
+ }
+ /* create fence */
+ req->cur_rel_fence = sync_fence_create("ppp-fence",
+ req->cur_rel_sync_pt);
+ if (req->cur_rel_fence == NULL) {
+ sync_pt_free(req->cur_rel_sync_pt);
+ req->cur_rel_sync_pt = NULL;
+ pr_err("%s: cannot create fence\n", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_2;
+ }
+ /* create fd */
+ return ret;
+buf_sync_err_2:
+ ppp_stat->timeline_value--;
+buf_sync_err_1:
+ for (i = 0; i < fence_cnt; i++)
+ sync_fence_put(req->acq_fen[i]);
+ req->acq_fen_cnt = 0;
+ return ret;
+}
+
+void mdp3_ppp_req_push(struct blit_req_queue *req_q, struct blit_req_list *req)
+{
+ int idx = req_q->push_idx;
+ req_q->req[idx] = *req;
+ req_q->count++;
+ req_q->push_idx = (req_q->push_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
+}
+
+struct blit_req_list *mdp3_ppp_next_req(struct blit_req_queue *req_q)
+{
+ struct blit_req_list *req;
+ if (req_q->count == 0)
+ return NULL;
+ req = &req_q->req[req_q->pop_idx];
+ return req;
+}
+
+void mdp3_ppp_req_pop(struct blit_req_queue *req_q)
+{
+ req_q->count--;
+ req_q->pop_idx = (req_q->pop_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
+}
+
+static void mdp3_ppp_blit_wq_handler(struct work_struct *work)
+{
+ struct msm_fb_data_type *mfd = ppp_stat->mfd;
+ struct blit_req_list *req;
+ int i, rc;
+
+ req = mdp3_ppp_next_req(&ppp_stat->req_q);
+ mutex_lock(&ppp_stat->config_ppp_mutex);
+
+ mdp3_iommu_enable(MDP3_CLIENT_PPP);
+ mdp3_ppp_turnon(mfd, 1);
+ while (req) {
+ mdp3_ppp_wait_for_fence(req);
+ for (i = 0; i < req->count; i++) {
+ if (!(req->req_list[i].flags & MDP_NO_BLIT)) {
+ /* Do the actual blit. */
+ rc = mdp3_ppp_start_blit(mfd,
+ &(req->req_list[i]),
+ &req->src_data[i],
+ &req->dst_data[i]);
+ if (rc)
+ break;
+ }
+ }
+ /* Signal to release fence */
+ mutex_lock(&ppp_stat->req_mutex);
+ mdp3_ppp_signal_timeline(req);
+ mdp3_ppp_req_pop(&ppp_stat->req_q);
+ req = mdp3_ppp_next_req(&ppp_stat->req_q);
+ if (ppp_stat->wait_for_pop)
+ complete(&ppp_stat->pop_q_comp);
+ mutex_unlock(&ppp_stat->req_mutex);
+ }
+ mdp3_ppp_turnon(mfd, 0);
+ mdp3_iommu_disable(MDP3_CLIENT_PPP);
+ mutex_unlock(&ppp_stat->config_ppp_mutex);
+}
+
+int mdp3_ppp_parse_req(void __user *p,
+ struct mdp_async_blit_req_list *req_list_header,
+ int async)
+{
+ struct blit_req_list *req;
+ struct blit_req_queue *req_q = &ppp_stat->req_q;
+ struct sync_fence *fence = NULL;
+ int count, rc, idx, i;
+ count = req_list_header->count;
+
+ mutex_lock(&ppp_stat->req_mutex);
+ while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) {
+ ppp_stat->wait_for_pop = true;
+ mutex_unlock(&ppp_stat->req_mutex);
+ rc = wait_for_completion_interruptible_timeout(
+ &ppp_stat->pop_q_comp, 5 * HZ);
+ if (rc == 0) {
+ /* This will only occur if there is serious problem */
+ pr_err("%s: timeout exiting queuing request\n",
+ __func__);
+ return -EBUSY;
+ }
+ mutex_lock(&ppp_stat->req_mutex);
+ ppp_stat->wait_for_pop = false;
+ }
+ idx = req_q->push_idx;
+ req = &req_q->req[idx];
+
+ if (copy_from_user(&req->req_list, p,
+ sizeof(struct mdp_blit_req) * count))
+ return -EFAULT;
+
+ rc = mdp3_ppp_handle_buf_sync(req, &req_list_header->sync);
+ if (rc < 0) {
+ pr_err("%s: Failed create sync point\n", __func__);
+ return rc;
+ }
+ req->count = count;
+
+ /* We need to grab ion handle while client thread */
+ for (i = 0; i < count; i++) {
+ rc = mdp3_ppp_get_img(&req->req_list[i].src,
+ &req->req_list[i], &req->src_data[i]);
+ if (rc < 0 || req->src_data[i].len == 0) {
+ pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
+ goto parse_err_1;
+ }
+
+ rc = mdp3_ppp_get_img(&req->req_list[i].dst,
+ &req->req_list[i], &req->dst_data[i]);
+ if (rc < 0 || req->dst_data[i].len == 0) {
+ mdp3_put_img(&req->src_data[i]);
+ pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
+ goto parse_err_1;
+ }
+ }
+
+ if (async) {
+ req->cur_rel_fen_fd = get_unused_fd_flags(0);
+ if (req->cur_rel_fen_fd < 0) {
+ pr_err("%s: get_unused_fd_flags failed\n", __func__);
+ rc = -ENOMEM;
+ goto parse_err_2;
+ }
+ sync_fence_install(req->cur_rel_fence, req->cur_rel_fen_fd);
+ rc = copy_to_user(req_list_header->sync.rel_fen_fd,
+ &req->cur_rel_fen_fd, sizeof(int));
+ if (rc) {
+ pr_err("%s:copy_to_user failed\n", __func__);
+ goto parse_err_3;
+ }
+ } else {
+ fence = req->cur_rel_fence;
+ }
+
+ mdp3_ppp_req_push(req_q, req);
+ mutex_unlock(&ppp_stat->req_mutex);
+ schedule_work(&ppp_stat->blit_work);
+ if (!async) {
+ /* wait for release fence */
+ rc = sync_fence_wait(fence,
+ 5 * MSEC_PER_SEC);
+ if (rc < 0)
+ pr_err("%s: sync blit! rc = %x\n", __func__, rc);
+
+ sync_fence_put(fence);
+ fence = NULL;
+ }
+ return 0;
+
+parse_err_3:
+ put_unused_fd(req->cur_rel_fen_fd);
+parse_err_2:
+ sync_fence_put(req->cur_rel_fence);
+ req->cur_rel_fence = NULL;
+ req->cur_rel_fen_fd = 0;
+parse_err_1:
+ for (i--; i >= 0; i--) {
+ mdp3_put_img(&req->src_data[i]);
+ mdp3_put_img(&req->dst_data[i]);
+ }
+ mdp3_ppp_deinit_buf_sync(req);
+ return rc;
+}
+
+int mdp3_ppp_res_init(struct msm_fb_data_type *mfd)
+{
+ const char timeline_name[] = "mdp3_ppp";
+ ppp_stat = kzalloc(sizeof(struct ppp_status), GFP_KERNEL);
+ if (!ppp_stat) {
+ pr_err("%s: kmalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ /*Setup sync_pt timeline for ppp*/
+ ppp_stat->timeline = sw_sync_timeline_create(timeline_name);
+ if (ppp_stat->timeline == NULL) {
+ pr_err("%s: cannot create time line\n", __func__);
+ return -ENOMEM;
+ } else {
+ ppp_stat->timeline_value = 1;
+ }
+
+ INIT_WORK(&ppp_stat->blit_work, mdp3_ppp_blit_wq_handler);
+ init_completion(&ppp_stat->pop_q_comp);
spin_lock_init(&ppp_stat->ppp_lock);
- mutex_init(&ppp_stat->config_mutex);
+ mutex_init(&ppp_stat->req_mutex);
+ mutex_init(&ppp_stat->config_ppp_mutex);
ppp_stat->busy = false;
+ ppp_stat->mfd = mfd;
mdp3_ppp_callback_setup();
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
index afac419..b4252ca 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.h
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -18,7 +18,7 @@
#define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val)
-#define MAX_BLIT_REQ 256
+#define MAX_BLIT_REQ 16
#define PPP_UPSCALE_MAX 64
#define PPP_BLUR_SCALE_MAX 128
#define PPP_LUT_MAX 256
@@ -403,11 +403,12 @@
void ppp_load_x_scale_table(int idx);
void ppp_load_y_scale_table(int idx);
-int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
- struct mdp_blit_req *req);
-int mdp3_ppp_res_init(void);
+int mdp3_ppp_res_init(struct msm_fb_data_type *mfd);
int mdp3_ppp_init(void);
int config_ppp_op_mode(struct ppp_blit_op *blit_op);
void ppp_enable(void);
+int mdp3_ppp_parse_req(void __user *p,
+ struct mdp_async_blit_req_list *req_list_header,
+ int async);
#endif
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 3bb4bdc..1311dab 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -120,6 +120,7 @@
struct early_suspend early_suspend;
void *debug_data;
+ int current_bus_idx;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 0918db1..13fba26 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/debugfs.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/printk.h>
@@ -438,3 +439,151 @@
return 0;
}
+
+static struct mdss_mdp_misr_map {
+ u32 ctrl_reg;
+ u32 value_reg;
+ u32 crc_op_mode;
+ u32 crc_index;
+ u32 crc_value[MISR_CRC_BATCH_SIZE];
+} mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
+ [DISPLAY_MISR_DSI0] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
+ },
+ [DISPLAY_MISR_DSI1] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
+ },
+ [DISPLAY_MISR_EDP] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
+ },
+ [DISPLAY_MISR_HDMI] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
+ },
+};
+
+static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
+{
+ struct mdss_mdp_misr_map *map;
+
+ if (block_id > DISPLAY_MISR_LCDC) {
+ pr_err("MISR Block id (%d) out of range\n", block_id);
+ return NULL;
+ }
+
+ map = mdss_mdp_misr_table + block_id;
+ if ((map->ctrl_reg == 0) || (map->value_reg == 0)) {
+ pr_err("MISR Block id (%d) config not found\n", block_id);
+ return NULL;
+ }
+
+ return map;
+}
+
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 config = 0;
+
+ map = mdss_misr_get_map(req->block_id);
+ if (!map) {
+ pr_err("Invalid MISR Block=%d\n", req->block_id);
+ return -EINVAL;
+ }
+
+ map->crc_op_mode = req->crc_op_mode;
+ memset(map->crc_value, 0, sizeof(map->crc_value));
+
+ pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
+ req->block_id, req->frame_count);
+
+ config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
+ (MDSS_MDP_LP_MISR_CTRL_ENABLE);
+
+ writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
+ mdata->mdp_base + map->ctrl_reg);
+ /* ensure clear is done */
+ wmb();
+ if (MISR_OP_BM == map->crc_op_mode) {
+ writel_relaxed(MISR_CRC_BATCH_CFG,
+ mdata->mdp_base + map->ctrl_reg);
+ } else {
+ writel_relaxed(config,
+ mdata->mdp_base + map->ctrl_reg);
+
+ config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+ pr_debug("MISR_CTRL = 0x%x", config);
+ }
+ return 0;
+}
+
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 status;
+ int ret = 0;
+ int i;
+
+ map = mdss_misr_get_map(resp->block_id);
+ if (!map) {
+ pr_err("Invalid MISR Block=%d\n", resp->block_id);
+ return -EINVAL;
+ }
+
+ switch (map->crc_op_mode) {
+ case MISR_OP_SFM:
+ case MISR_OP_MFM:
+ ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
+ status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
+ MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+
+ pr_debug("Status of Get MISR_CTRL = 0x%x", status);
+ if (ret == 0) {
+ resp->crc_value[0] =
+ readl_relaxed(mdata->mdp_base + map->value_reg);
+ pr_debug("CRC %d=0x%x\n", resp->block_id,
+ resp->crc_value[0]);
+ } else {
+ pr_warn("MISR %d busy with status 0x%x\n",
+ resp->block_id, status);
+ }
+ break;
+ case MISR_OP_BM:
+ for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+ resp->crc_value[i] = map->crc_value[i];
+ map->crc_index = 0;
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+/* This function is expected to be called from interrupt context */
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 status, config;
+
+ map = mdss_misr_get_map(block_id);
+ if (!map || (map->crc_op_mode != MISR_OP_BM))
+ return;
+
+ config = MISR_CRC_BATCH_CFG;
+
+ status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+ if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
+ map->crc_value[map->crc_index] =
+ readl_relaxed(mdata->mdp_base + map->value_reg);
+ map->crc_index++;
+ if (map->crc_index == MISR_CRC_BATCH_SIZE)
+ map->crc_index = 0;
+ config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
+ }
+ writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
+}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 167fa8a..29eb16c 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.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
@@ -16,24 +16,30 @@
#include "mdss.h"
+#define MISR_POLL_SLEEP 2000
+#define MISR_POLL_TIMEOUT 32000
+#define MISR_CRC_BATCH_SIZE 32
+#define MISR_CRC_BATCH_CFG 0x101
+
#ifdef CONFIG_DEBUG_FS
int mdss_debugfs_init(struct mdss_data_type *mdata);
int mdss_debugfs_remove(struct mdss_data_type *mdata);
int mdss_debug_register_base(const char *name, void __iomem *base,
size_t max_offset);
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
#else
-static inline int mdss_debugfs_init(struct mdss_data_type *mdata)
-{
- return 0;
-}
+static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
-{
- return 0;
-}
+{ return 0; }
static inline int mdss_debug_register_base(const char *name, void __iomem *base,
- size_t max_offset)
-{
- return 0;
-}
+ size_t max_offset) { return 0; }
+static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
+ struct mdp_misr *reg) { return 0; }
+static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
+ struct mdp_misr *resp) { return 0; }
+static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
+ int block_id) { }
#endif
#endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index db3cecc..afabc20 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -432,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;
@@ -618,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);
@@ -651,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)
{
@@ -684,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;
@@ -692,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 {
@@ -712,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;
@@ -1110,6 +1123,7 @@
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) {
@@ -1139,6 +1153,8 @@
}
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));
@@ -1164,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 c78c5cf..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
@@ -332,7 +330,7 @@
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;
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 6b210af..72e3c64 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -212,7 +212,7 @@
int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
{
- dp->start = kmalloc(size, GFP_KERNEL);
+ dp->start = dma_alloc_writecombine(NULL, size, &dp->dmap, GFP_KERNEL);
if (dp->start == NULL) {
pr_err("%s:%u\n", __func__, __LINE__);
return -ENOMEM;
@@ -237,7 +237,7 @@
struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
- int i, len;
+ int i, len = 0;
dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
@@ -268,8 +268,9 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ len += DSI_HOST_HDR_SIZE;
- return dp->len;
+ return len;
}
/*
@@ -312,8 +313,7 @@
}
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
@@ -356,7 +356,7 @@
}
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
@@ -367,7 +367,7 @@
struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
- int i, len;
+ int i, len = 0;
dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
@@ -402,7 +402,8 @@
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return dp->len;
+ len += DSI_HOST_HDR_SIZE;
+ return len;
}
/*
@@ -436,7 +437,7 @@
*hp |= DSI_HDR_DATA2(0);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
- return dp->len;
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
@@ -467,8 +468,7 @@
*hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len;
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
* mipi dsi dcs read with 0 parameters
@@ -498,8 +498,7 @@
*hp |= DSI_HDR_DATA2(0);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -517,8 +516,7 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -536,8 +534,7 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -555,8 +552,7 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -574,8 +570,7 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -601,8 +596,7 @@
*hp |= DSI_HDR_DATA2(cm->payload[1]);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -622,8 +616,7 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
@@ -643,8 +636,7 @@
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
-
- return dp->len; /* 4 bytes */
+ return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
@@ -1134,12 +1126,44 @@
return 4;
}
-
static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_buf *tp);
static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_buf *rp, int rlen);
+
+static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int cnt)
+{
+ struct dsi_buf *tp;
+ struct dsi_cmd_desc *cm;
+ struct dsi_ctrl_hdr *dchdr;
+ int len, tot = 0;
+
+ tp = &ctrl->tx_buf;
+ mdss_dsi_buf_init(tp);
+ cm = cmds;
+ len = 0;
+ while (cnt--) {
+ dchdr = &cm->dchdr;
+ mdss_dsi_buf_reserve(tp, len);
+ len = mdss_dsi_cmd_dma_add(tp, cm);
+ tot += len;
+ if (dchdr->last) {
+ tp->data = tp->start; /* begin of buf */
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (dchdr->wait)
+ usleep(dchdr->wait * 1000);
+
+ mdss_dsi_buf_init(tp);
+ len = 0;
+ }
+ cm++;
+ }
+ return tot;
+}
+
/*
* mdss_dsi_cmds_tx:
* thread context only
@@ -1147,11 +1171,8 @@
int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int cnt)
{
- struct dsi_buf *tp;
- struct dsi_cmd_desc *cm;
- struct dsi_ctrl_hdr *dchdr;
u32 dsi_ctrl, data;
- int i, video_mode;
+ int video_mode;
if (ctrl->shared_pdata.broadcast_enable) {
if (ctrl->ndx == DSI_CTRL_0) {
@@ -1187,18 +1208,7 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
}
- tp = &ctrl->tx_buf;
- cm = cmds;
- for (i = 0; i < cnt; i++) {
- mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
- mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, cm);
- mdss_dsi_cmd_dma_tx(ctrl, tp);
- dchdr = &cm->dchdr;
- if (dchdr->wait)
- usleep(dchdr->wait * 1000);
- cm++;
- }
+ mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
if (video_mode)
MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
@@ -1350,11 +1360,6 @@
len = ALIGN(tp->len, 4);
size = ALIGN(tp->len, SZ_4K);
- tp->dmap = dma_map_single(&dsi_dev, tp->data, size, DMA_TO_DEVICE);
- if (dma_mapping_error(&dsi_dev, tp->dmap)) {
- pr_err("%s: dmap mapp failed\n", __func__);
- return -ENOMEM;
- }
if (is_mdss_iommu_attached()) {
int ret = msm_iommu_map_contig_buffer(tp->dmap,
@@ -1399,8 +1404,6 @@
msm_iommu_unmap_contig_buffer(addr,
mdss_get_iommu_domain(domain), 0, size);
- dma_unmap_single(&dsi_dev, tp->dmap, size, DMA_TO_DEVICE);
- tp->dmap = 0;
return tp->len;
}
@@ -1438,6 +1441,13 @@
void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
{
unsigned long flag;
+ u32 data;
+
+ /* DSI_INTL_CTRL */
+ data = MIPI_INP((ctrl->ctrl_base) + 0x0110);
+ data |= DSI_INTR_VIDEO_DONE_MASK;
+
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data);
spin_lock_irqsave(&ctrl->mdp_lock, flag);
INIT_COMPLETION(ctrl->video_comp);
@@ -1446,6 +1456,10 @@
wait_for_completion_timeout(&ctrl->video_comp,
msecs_to_jiffies(VSYNC_PERIOD * 4));
+
+ data = MIPI_INP((ctrl->ctrl_base) + 0x0110);
+ data &= ~DSI_INTR_VIDEO_DONE_MASK;
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data);
}
static void mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
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..e16f2df 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -96,13 +96,14 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
if (!mfd)
pr_err("%s mfd NULL\n", __func__);
+ mfd->no_update.value = NOTIFY_TYPE_NO_UPDATE;
complete(&mfd->no_update.comp);
}
static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
unsigned long *argp)
{
- int ret, notify;
+ int ret, notify, to_user;
ret = copy_from_user(¬ify, argp, sizeof(int));
if (ret) {
@@ -117,17 +118,20 @@
INIT_COMPLETION(mfd->update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
+ to_user = mfd->update.value;
} else {
INIT_COMPLETION(mfd->no_update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
+ to_user = mfd->no_update.value;
}
if (ret == 0)
ret = -ETIMEDOUT;
- return (ret > 0) ? 0 : ret;
+ else if (ret > 0)
+ ret = copy_to_user(argp, &to_user, sizeof(int));
+ return ret;
}
-#define MAX_BACKLIGHT_BRIGHTNESS 255
static int lcd_backlight_registered;
static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
@@ -136,25 +140,28 @@
struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
int bl_lvl;
- if (value > MAX_BACKLIGHT_BRIGHTNESS)
- value = MAX_BACKLIGHT_BRIGHTNESS;
+ if (value > MDSS_MAX_BL_BRIGHTNESS)
+ value = MDSS_MAX_BL_BRIGHTNESS;
/* This maps android backlight level 0 to 255 into
driver backlight level 0 to bl_max with rounding */
- bl_lvl = (2 * value * mfd->panel_info->bl_max +
- MAX_BACKLIGHT_BRIGHTNESS) / (2 * MAX_BACKLIGHT_BRIGHTNESS);
+ MDSS_BRIGHT_TO_BL(bl_lvl, value, mfd->panel_info->bl_max,
+ MDSS_MAX_BL_BRIGHTNESS);
if (!bl_lvl && value)
bl_lvl = 1;
- mutex_lock(&mfd->bl_lock);
- mdss_fb_set_backlight(mfd, bl_lvl);
- mutex_unlock(&mfd->bl_lock);
+ if (!IS_CALIB_MODE_BL(mfd) && (!mfd->ext_bl_ctrl || !value ||
+ !mfd->bl_level)) {
+ mutex_lock(&mfd->bl_lock);
+ mdss_fb_set_backlight(mfd, bl_lvl);
+ mutex_unlock(&mfd->bl_lock);
+ }
}
static struct led_classdev backlight_led = {
.name = "lcd-backlight",
- .brightness = MAX_BACKLIGHT_BRIGHTNESS,
+ .brightness = MDSS_MAX_BL_BRIGHTNESS,
.brightness_set = mdss_fb_set_bl_brightness,
};
@@ -535,7 +542,7 @@
struct mdss_panel_data *pdata;
u32 temp = bkl_lvl;
- if (!mfd->panel_power_on || !bl_updated) {
+ if ((!mfd->panel_power_on || !bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
unset_bl_level = bkl_lvl;
return;
} else {
@@ -545,7 +552,8 @@
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
- mdss_fb_scale_bl(mfd, &temp);
+ if (!IS_CALIB_MODE_BL(mfd))
+ mdss_fb_scale_bl(mfd, &temp);
/*
* Even though backlight has been scaled, want to show that
* backlight has been set to bkl_lvl to those that read from
@@ -603,6 +611,9 @@
ret = mfd->mdp.on_fnc(mfd);
if (ret == 0)
mfd->panel_power_on = true;
+ mutex_lock(&mfd->update.lock);
+ mfd->update.type = NOTIFY_TYPE_UPDATE;
+ mutex_unlock(&mfd->update.lock);
}
break;
@@ -614,7 +625,11 @@
if (mfd->panel_power_on && mfd->mdp.off_fnc) {
int curr_pwr_state;
+ mutex_lock(&mfd->update.lock);
+ mfd->update.type = NOTIFY_TYPE_SUSPEND;
+ mutex_unlock(&mfd->update.lock);
del_timer(&mfd->no_update.timer);
+ mfd->no_update.value = NOTIFY_TYPE_SUSPEND;
complete(&mfd->no_update.comp);
mfd->op_enable = false;
@@ -669,22 +684,16 @@
}
mdss_fb_pan_idle(mfd);
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- if (info->var.accel_flags) {
- mutex_unlock(&info->lock);
- return -EINVAL;
- }
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
- }
/* Set VM flags. */
start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
+ if ((vma->vm_end <= vma->vm_start) ||
+ (off >= len) ||
+ ((vma->vm_end - vma->vm_start) > (len - off)))
return -EINVAL;
off += start;
+ if (off < start)
+ return -EINVAL;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
@@ -971,6 +980,7 @@
mfd->op_enable = true;
+ mutex_init(&mfd->update.lock);
mutex_init(&mfd->no_update.lock);
mutex_init(&mfd->sync_mutex);
init_timer(&mfd->no_update.timer);
@@ -1725,7 +1735,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_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 05fdec4..98bca03 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -26,7 +26,7 @@
#define MSM_FB_MAX_DEV_LIST 32
#define MSM_FB_ENABLE_DBGFS
-#define WAIT_FENCE_FIRST_TIMEOUT MSEC_PER_SEC
+#define WAIT_FENCE_FIRST_TIMEOUT (3 * MSEC_PER_SEC)
#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC)
/* Display op timeout should be greater than total timeout */
#define WAIT_DISP_OP_TIMEOUT ((WAIT_FENCE_FIRST_TIMEOUT + \
@@ -50,6 +50,7 @@
struct timer_list timer;
struct completion comp;
struct mutex lock;
+ int value;
};
struct msm_fb_data_type;
@@ -74,6 +75,12 @@
void *private1;
};
+#define IS_CALIB_MODE_BL(mfd) (((mfd)->calib_mode) & MDSS_CALIB_MODE_BL)
+#define MDSS_BRIGHT_TO_BL(out, v, bl_max, max_bright) do {\
+ out = (2 * (v) * (bl_max) + max_bright)\
+ / (2 * max_bright);\
+ } while (0)
+
struct msm_fb_data_type {
u32 key;
u32 index;
@@ -101,6 +108,8 @@
unsigned long cursor_buf_phys;
unsigned long cursor_buf_iova;
+ u32 ext_bl_ctrl;
+ u32 calib_mode;
u32 bl_level;
u32 bl_scale;
u32 bl_min_lvl;
@@ -141,6 +150,25 @@
struct mdp_display_commit disp_commit;
};
+static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
+{
+ int needs_complete = 0;
+ mutex_lock(&mfd->update.lock);
+ mfd->update.value = mfd->update.type;
+ needs_complete = mfd->update.value == NOTIFY_TYPE_UPDATE;
+ mutex_unlock(&mfd->update.lock);
+ if (needs_complete) {
+ complete(&mfd->update.comp);
+ mutex_lock(&mfd->no_update.lock);
+ if (mfd->no_update.timer.function)
+ del_timer(&(mfd->no_update.timer));
+
+ mfd->no_update.timer.expires = jiffies + (2 * HZ);
+ add_timer(&mfd->no_update.timer);
+ mutex_unlock(&mfd->no_update.lock);
+ }
+}
+
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index fe10189..287f2cd 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -391,6 +391,10 @@
return rc;
}
+ if (hdmi_ctrl->mhl_max_pclk && hpd &&
+ (!hdmi_ctrl->mhl_hpd_on || hdmi_ctrl->hpd_feature_on))
+ return 0;
+
if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
@@ -2508,6 +2512,9 @@
return -EINVAL;
}
+ /* mhl status should override */
+ hdmi_ctrl->mhl_hpd_on = on;
+
if (!on && hdmi_ctrl->hpd_feature_on) {
rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
} else if (on && !hdmi_ctrl->hpd_feature_on) {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index ce3c00c..d4f8e67 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -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
@@ -62,6 +62,7 @@
u32 hpd_initialized;
u8 timing_gen_on;
u32 mhl_max_pclk;
+ u8 mhl_hpd_on;
struct completion hpd_done;
struct work_struct hpd_int_work;
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index ff52e4c..809db43 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -276,15 +276,17 @@
DEV_DBG("%pS->%s: %s disable\n",
__builtin_return_address(0), __func__,
in_gpio[i].gpio_name);
-
- gpio_free(in_gpio[i].gpio);
+ if (in_gpio[i].gpio)
+ gpio_free(in_gpio[i].gpio);
}
}
return rc;
disable_gpio:
for (i--; i >= 0; i--)
- gpio_free(in_gpio[i].gpio);
+ if (in_gpio[i].gpio)
+ gpio_free(in_gpio[i].gpio);
+
return rc;
} /* msm_dss_enable_gpio */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 772545f..c4bf67e 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -345,7 +345,6 @@
int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota)
{
- static int current_bus_idx;
int bus_idx;
if (mdss_res->bus_hdl < 1) {
@@ -359,9 +358,10 @@
int num_cases = mdp_bus_scale_table.num_usecases;
struct msm_bus_vectors *vect = NULL;
- bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+ bus_idx = (mdss_res->current_bus_idx % (num_cases - 1)) + 1;
- vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+ vect = mdp_bus_scale_table.usecase[mdss_res->current_bus_idx].
+ vectors;
/* avoid performing updates for small changes */
if ((ALIGN(ab_quota, SZ_64M) == ALIGN(vect->ab, SZ_64M)) &&
@@ -377,7 +377,7 @@
pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx,
vect->ab, vect->ib);
}
- current_bus_idx = bus_idx;
+ mdss_res->current_bus_idx = bus_idx;
return msm_bus_scale_client_update_request(mdss_res->bus_hdl, bus_idx);
}
@@ -626,8 +626,14 @@
if (mdata->vsync_ena)
mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
- if (!enable)
+ if (!enable) {
+ msm_bus_scale_client_update_request(
+ mdss_res->bus_hdl, 0);
pm_runtime_put(&mdata->pdev->dev);
+ } else {
+ msm_bus_scale_client_update_request(
+ mdss_res->bus_hdl, mdss_res->current_bus_idx);
+ }
}
mutex_unlock(&mdp_clk_lock);
@@ -977,6 +983,7 @@
goto probe_done;
}
mdata->irq = res->start;
+ mdss_mdp_hw.ptr = mdata;
/*populate hw iomem base info from device tree*/
rc = mdss_mdp_parse_dt(pdev);
@@ -1023,6 +1030,7 @@
probe_done:
if (IS_ERR_VALUE(rc)) {
+ mdss_mdp_hw.ptr = NULL;
mdss_res = NULL;
mdss_mdp_pp_term(&pdev->dev);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f3b5acec..f59cdaa 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -157,6 +157,7 @@
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*wait_pingpong) (struct mdss_mdp_ctl *ctl, void *arg);
u32 (*read_line_cnt_fnc) (struct mdss_mdp_ctl *);
int (*add_vsync_handler) (struct mdss_mdp_ctl *,
struct mdss_mdp_vsync_handler *);
@@ -264,6 +265,9 @@
u32 last_str;
u32 last_bl;
u32 calc_itr;
+ uint32_t bl_bright_shift;
+ uint32_t bl_lin[AD_BL_LIN_LEN];
+ uint32_t bl_lin_inv[AD_BL_LIN_LEN];
};
struct pp_sts_type {
@@ -436,6 +440,7 @@
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl);
int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
ktime_t *wakeup_time);
@@ -491,6 +496,8 @@
int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
struct mdss_ad_input *input, int wait);
int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off);
+int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
+ struct mdss_calib_cfg *cfg);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
u32 type);
@@ -503,6 +510,7 @@
int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe);
void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
@@ -536,6 +544,9 @@
int mdss_panel_register_done(struct mdss_panel_data *pdata);
int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
+
+int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 4b763aa..1cd2dbd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -23,7 +23,8 @@
/* truncate at 1k */
#define MDSS_MDP_BUS_FACTOR_SHIFT 10
/* 1.5 bus fudge factor */
-#define MDSS_MDP_BUS_FUDGE_FACTOR(val) (((val) / 2) * 3)
+#define MDSS_MDP_BUS_FUDGE_FACTOR_IB(val) (((val) / 2) * 3)
+#define MDSS_MDP_BUS_FUDGE_FACTOR_AB(val) (val << 1)
/* 1.25 clock fudge factor */
#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
@@ -81,7 +82,8 @@
}
if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
bus_ab_quota = bus_ib_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
- bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
+ bus_ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR_AB(bus_ab_quota);
+ bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR_IB(bus_ib_quota);
bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
@@ -1442,6 +1444,27 @@
return ret;
}
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl)
+{
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctl->lock);
+ if (ret)
+ return ret;
+
+ if (!ctl->power_on) {
+ mutex_unlock(&ctl->lock);
+ return 0;
+ }
+
+ if (ctl->wait_pingpong)
+ ret = ctl->wait_pingpong(ctl, NULL);
+
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_ctl *sctl = NULL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 6ec5b63..741c7a7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -515,4 +515,33 @@
MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
};
-#endif /* MDSS_MDP_HWIO_H */
+#define MDSS_MDP_LP_MISR_SEL 0x450
+#define MDSS_MDP_LP_MISR_CTRL_MDP 0x454
+#define MDSS_MDP_LP_MISR_CTRL_HDMI 0x458
+#define MDSS_MDP_LP_MISR_CTRL_EDP 0x45C
+#define MDSS_MDP_LP_MISR_CTRL_DSI0 0x460
+#define MDSS_MDP_LP_MISR_CTRL_DSI1 0x464
+
+#define MDSS_MDP_LP_MISR_SIGN_MDP 0x468
+#define MDSS_MDP_LP_MISR_SIGN_EDP 0x46C
+#define MDSS_MDP_LP_MISR_SIGN_HDMI 0x470
+#define MDSS_MDP_LP_MISR_SIGN_DSI0 0x474
+#define MDSS_MDP_LP_MISR_SIGN_DSI1 0x478
+
+#define MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK 0xFF
+#define MDSS_MDP_LP_MISR_CTRL_ENABLE BIT(8)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS BIT(9)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR BIT(10)
+
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_BLEND 0x08
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_GC 0x09
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_BLEND 0x0A
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_GC 0x0B
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_BLEND 0x0C
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_GC 0x0D
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_BLEND 0x0E
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_GC 0x0F
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_BLEND 0x10
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_GC 0x11
+
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index afbbe55..bd4f3ea 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -335,32 +335,12 @@
mutex_unlock(&ctx->clk_mtx);
}
-static int mdss_mdp_cmd_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
-{
- struct mdss_mdp_cmd_ctx *ctx;
- int rc;
-
- ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
- if (!ctx) {
- pr_err("invalid ctx\n");
- return -ENODEV;
- }
-
- pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
-
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- KOFF_TIMEOUT);
- WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
-
- return 0;
-}
-
-int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
unsigned long flags;
int need_wait = 0;
- int rc;
+ int rc = 0;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
if (!ctx) {
@@ -377,11 +357,29 @@
__func__, need_wait, ctl->intf_num, ctx);
if (need_wait) {
- rc = wait_for_completion_interruptible_timeout(
+ rc = wait_for_completion_timeout(
&ctx->pp_comp, KOFF_TIMEOUT);
- WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+ if (rc <= 0) {
+ WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
rc, ctl->num);
+ rc = -EPERM;
+ } else
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ int rc;
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
}
if (ctx->panel_on == 0) {
@@ -442,7 +440,7 @@
null_handle.vsync_handler = NULL;
mdss_mdp_cmd_vsync_ctrl(ctl, &null_handle);
- mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
NULL, NULL);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
NULL, NULL);
@@ -456,6 +454,12 @@
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+ ctl->stop_fnc = NULL;
+ ctl->display_fnc = NULL;
+ ctl->wait_pingpong = NULL;
+ ctl->add_vsync_handler = NULL;
+ ctl->remove_vsync_handler = NULL;
+
pr_debug("%s:-\n", __func__);
return 0;
@@ -519,7 +523,7 @@
ctl->stop_fnc = mdss_mdp_cmd_stop;
ctl->display_fnc = mdss_mdp_cmd_kickoff;
- ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
+ ctl->wait_pingpong = mdss_mdp_cmd_wait4pingpong;
ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
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_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 0c08eda..e06695f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -349,8 +349,13 @@
rc = wait_for_completion_interruptible_timeout(&ctx->wb_comp,
KOFF_TIMEOUT);
- WARN(rc <= 0, "writeback kickoff timed out (%d) ctl=%d\n",
- rc, ctl->num);
+ if (rc <= 0) {
+ rc = -ENODEV;
+ WARN(1, "writeback kickoff timed out (%d) ctl=%d\n",
+ rc, ctl->num);
+ } else {
+ rc = 0;
+ }
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); /* clock off */
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c96464a..fcaa80b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -27,6 +27,7 @@
#include <mach/event_timer.h>
#include "mdss.h"
+#include "mdss_debug.h"
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
@@ -173,22 +174,6 @@
return -EINVAL;
}
- if ((fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
- fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1) &&
- ((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w)) {
- pr_err("too much YUV upscaling Width %d->%d\n",
- req->src_rect.w, req->dst_rect.w);
- return -EINVAL;
- }
-
- if ((fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
- fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2) &&
- (req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) {
- pr_err("too much YUV upscaling Height %d->%d\n",
- req->src_rect.h, req->dst_rect.h);
- return -EINVAL;
- }
-
if (req->flags & MDP_BWC_EN) {
if ((req->src.width != req->src_rect.w) ||
(req->src.height != req->src_rect.h)) {
@@ -196,6 +181,25 @@
return -EINVAL;
}
}
+
+ if (req->flags & MDP_DEINTERLACE) {
+ if (req->flags & MDP_SOURCE_ROTATED_90) {
+ if ((req->src_rect.w % 4) != 0) {
+ pr_err("interlaced rect not h/4\n");
+ return -EINVAL;
+ }
+ } else if ((req->src_rect.h % 4) != 0) {
+ pr_err("interlaced rect not h/4\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ if (req->flags & MDP_DEINTERLACE) {
+ if ((req->src_rect.h % 4) != 0) {
+ pr_err("interlaced rect h not multiple of 4\n");
+ return -EINVAL;
+ }
+ }
}
if (fmt->is_yuv) {
@@ -206,13 +210,6 @@
}
}
- if (req->flags & MDP_DEINTERLACE) {
- if ((req->src.width % 4 != 0) || (req->src.height % 4 != 0)) {
- pr_err("interlaced fmt w,h need to be even post div\n");
- return -EINVAL;
- }
- }
-
return 0;
}
@@ -299,7 +296,7 @@
struct mdss_mdp_format_params *fmt;
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_mixer *mixer = NULL;
- u32 pipe_type, mixer_mux, len, src_format;
+ u32 pipe_type, mixer_mux, len;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdp_histogram_start_req hist;
int ret;
@@ -327,13 +324,13 @@
pr_debug("pipe ctl=%u req id=%x mux=%d\n", mdp5_data->ctl->num, req->id,
mixer_mux);
- src_format = req->src.format;
if (req->flags & (MDP_SOURCE_ROTATED_90 | MDP_BWC_EN))
- src_format = mdss_mdp_get_rotator_dst_format(src_format);
+ req->src.format =
+ mdss_mdp_get_rotator_dst_format(req->src.format);
- fmt = mdss_mdp_get_format_params(src_format);
+ fmt = mdss_mdp_get_format_params(req->src.format);
if (!fmt) {
- pr_err("invalid pipe format %d\n", src_format);
+ pr_err("invalid pipe format %d\n", req->src.format);
return -EINVAL;
}
@@ -695,13 +692,22 @@
int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_pipe *pipe, *next;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret;
mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
- list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
+
+ ret = mdss_mdp_display_wait4pingpong(mdp5_data->ctl);
+ if (ret) {
+ mutex_unlock(&mfd->lock);
+ mutex_unlock(&mdp5_data->ov_lock);
+ return ret;
+ }
+
+ list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
+ used_list) {
struct mdss_mdp_data *buf;
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
@@ -709,6 +715,13 @@
pipe->params_changed++;
buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
+ if (pipe->mixer) {
+ if (!mdss_mdp_pipe_is_staged(pipe)) {
+ list_del(&pipe->used_list);
+ list_add(&pipe->cleanup_list,
+ &mdp5_data->pipes_cleanup);
+ }
+ }
continue;
} else if (pipe->front_buf.num_planes) {
buf = &pipe->front_buf;
@@ -741,15 +754,7 @@
ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
- complete(&mfd->update.comp);
- mutex_lock(&mfd->no_update.lock);
- if (mfd->no_update.timer.function)
- del_timer(&(mfd->no_update.timer));
-
- mfd->no_update.timer.expires = jiffies + (2 * HZ);
- add_timer(&mfd->no_update.timer);
- mutex_unlock(&mfd->no_update.lock);
-
+ mdss_fb_update_notify_update(mfd);
commit_fail:
mdss_mdp_overlay_cleanup(mfd);
@@ -1286,20 +1291,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);
@@ -1554,8 +1553,16 @@
copyback = 1;
}
break;
+ case mdp_op_calib_cfg:
+ ret = mdss_mdp_calib_config((struct mdp_calib_config_data *)
+ &mdp_pp.data.calib_cfg, ©back);
+ break;
+ case mdp_op_calib_mode:
+ ret = mdss_mdp_calib_mode(mfd, &mdp_pp.data.mdss_calib_cfg);
+ break;
default:
- pr_err("Unsupported request to MDP_PP IOCTL.\n");
+ pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n",
+ mdp_pp.op);
ret = -EINVAL;
break;
}
@@ -1614,6 +1621,7 @@
static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
int ret = 0;
switch (metadata->op) {
case metadata_op_vic:
@@ -1623,6 +1631,11 @@
else
ret = -EINVAL;
break;
+ case metadata_op_crc:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+ ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
+ break;
default:
pr_warn("unsupported request to MDP META IOCTL\n");
ret = -EINVAL;
@@ -1649,6 +1662,7 @@
static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
int ret = 0;
switch (metadata->op) {
case metadata_op_frame_rate:
@@ -1658,6 +1672,11 @@
case metadata_op_get_caps:
ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
break;
+ case metadata_op_crc:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+ ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
+ break;
default:
pr_warn("Unsupported request to MDP META IOCTL.\n");
ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 4f9ab81..3b91ced 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -22,6 +22,7 @@
#define SMP_MB_SIZE (mdss_res->smp_mb_size)
#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
#define SMP_ENTRIES_PER_MB (SMP_MB_SIZE / 16)
+#define SMP_MB_ENTRY_SIZE 16
#define MAX_BPP 4
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
@@ -95,17 +96,31 @@
static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
{
- u32 entries, val, wm[3];
+ u32 fetch_size, val, wm[3];
- entries = mb_cnt * SMP_ENTRIES_PER_MB;
- val = entries >> 2;
+ fetch_size = mb_cnt * SMP_MB_SIZE;
+
+ /*
+ * when doing hflip, one line is reserved to be consumed down the
+ * pipeline. This line will always be marked as full even if it doesn't
+ * have any data. In order to generate proper priority levels ignore
+ * this region while setting up watermark levels
+ */
+ if (pipe->flags & MDP_FLIP_LR) {
+ u8 bpp = pipe->src_fmt->is_yuv ? 1 :
+ pipe->src_fmt->bpp;
+ fetch_size -= (pipe->src.w * bpp);
+ }
+
+ /* 1/4 of SMP pool that is being fetched */
+ val = (fetch_size / SMP_MB_ENTRY_SIZE) >> 2;
wm[0] = val;
wm[1] = wm[0] + val;
wm[2] = wm[1] + val;
- pr_debug("pnum=%d watermarks %u,%u,%u\n", pipe->num,
- wm[0], wm[1], wm[2]);
+ pr_debug("pnum=%d fetch_size=%u watermarks %u,%u,%u\n", pipe->num,
+ fetch_size, wm[0], wm[1], wm[2]);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0, wm[0]);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1, wm[1]);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2, wm[2]);
@@ -139,7 +154,7 @@
u32 num_blks = 0, reserved = 0;
struct mdss_mdp_plane_sizes ps;
int i;
- int rc = 0;
+ int rc = 0, rot_mode = 0;
u32 nlines;
if (pipe->bwc_mode) {
@@ -153,23 +168,32 @@
ps.num_planes = 2;
ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
ps.ystride[1] = pipe->src.h >> pipe->vert_deci;
- } else if (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
- ps.ystride[0] = max(pipe->mixer->width, pipe->src.w) * MAX_BPP;
- ps.num_planes = 1;
} else {
rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
pipe->src.w, pipe->src.h, &ps, 0);
if (rc)
return rc;
+
+ if (pipe->mixer && pipe->mixer->rotator_mode)
+ rot_mode = 1;
+ else if (ps.num_planes == 1)
+ ps.ystride[0] = MAX_BPP *
+ max(pipe->mixer->width, pipe->src.w);
}
+ nlines = pipe->bwc_mode ? 1 : 2;
+
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < ps.num_planes; i++) {
- nlines = pipe->bwc_mode ? ps.rau_h[i] : 2;
- num_blks = DIV_ROUND_UP(nlines * ps.ystride[i], SMP_MB_SIZE);
+ if (rot_mode) {
+ num_blks = 1;
+ } else {
+ num_blks = DIV_ROUND_UP(ps.ystride[i] * nlines,
+ SMP_MB_SIZE);
- if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
- num_blks = roundup_pow_of_two(num_blks);
+ if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
+ num_blks = roundup_pow_of_two(num_blks);
+ }
pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
num_blks, pipe->num, i);
@@ -206,6 +230,13 @@
return 0;
}
+void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe)
+{
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_smp_free(pipe);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size)
{
if (!mdata)
@@ -694,3 +725,8 @@
return ret;
}
+
+int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe)
+{
+ return (pipe == pipe->mixer->stage_pipe[pipe->mixer_stage]);
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 9d28265..5d7a0c9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -190,6 +190,7 @@
#define PP_AD_STATE_DATA 0x8
#define PP_AD_STATE_RUN 0x10
#define PP_AD_STATE_VSYNC 0x20
+#define PP_AD_STATE_BL_LIN 0x40
#define PP_AD_STATE_IS_INITCFG(st) (((st) & PP_AD_STATE_INIT) &&\
((st) & PP_AD_STATE_CFG))
@@ -217,6 +218,8 @@
#define MDSS_AD_MODE_DATA_MATCH(mode, data) ((1 << (mode)) & (data))
#define MDSS_AD_RUNNING_AUTO_BL(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
((ad)->cfg.mode == MDSS_AD_MODE_AUTO_BL))
+#define MDSS_AD_RUNNING_AUTO_STR(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
+ ((ad)->cfg.mode == MDSS_AD_MODE_AUTO_STR))
#define SHARP_STRENGTH_DEFAULT 32
#define SHARP_EDGE_THR_DEFAULT 112
@@ -1019,6 +1022,8 @@
int i, ret = 0;
struct mdss_data_type *mdata;
struct mdss_mdp_ctl *ctl;
+ u32 mixer_cnt;
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
return -EINVAL;
@@ -1043,11 +1048,17 @@
else
flags = 0;
- if (dspp_num < mdata->nad_cfgs) {
+ mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+ if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2) &&
+ ctl->mfd->panel_info->type != MIPI_CMD_PANEL) {
ret = mdss_mdp_ad_setup(ctl->mfd);
if (ret < 0)
pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
}
+ /* call calibration specific processing here */
+ if (ctl->mfd->calib_mode)
+ goto flush_exit;
+
/* nothing to update */
if ((!flags) && (!(opmode)) && (ret <= 0))
goto dspp_exit;
@@ -1138,6 +1149,7 @@
if (pp_sts->pgc_sts & PP_STS_ENABLE)
opmode |= (1 << 22);
+flush_exit:
writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num));
wmb();
@@ -1199,7 +1211,7 @@
*/
int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
{
- u32 flags = 0, disp_num;
+ u32 flags = 0, disp_num, bl;
struct pp_sts_type pp_sts;
struct mdss_ad_info *ad;
struct mdss_data_type *mdata = ctl->mdata;
@@ -1216,8 +1228,15 @@
pp_ad_cfg_write(ad);
if (PP_AD_STATE_INIT & ad->state)
pp_ad_init_write(ad);
- if (PP_AD_STATE_DATA & ad->state)
- pp_ad_input_write(ad, ctl->mfd->bl_level);
+ if (PP_AD_STATE_DATA & ad->state) {
+ bl = ctl->mfd->bl_level;
+ ad->last_bl = bl;
+ if (ad->state & PP_AD_STATE_BL_LIN) {
+ bl = ad->bl_lin[bl >> ad->bl_bright_shift];
+ bl = bl << ad->bl_bright_shift;
+ }
+ pp_ad_input_write(ad, bl);
+ }
if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
ctl->add_vsync_handler(ctl, &ad->handle);
}
@@ -1652,6 +1671,9 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if (config->len != IGC_LUT_ENTRIES)
+ return -EINVAL;
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2742,12 +2764,20 @@
{
struct mdss_ad_info *ad;
struct mdss_ad_input input;
+ struct mdss_mdp_ctl *ctl;
- ad = mdss_mdp_get_ad(mfd);
- if (!ad)
+ if (!mfd)
+ return -EINVAL;
+ ctl = mfd_to_ctl(mfd);
+ if (!ctl)
return -EINVAL;
- pr_debug("backlight level changed, trigger update to AD");
+ ad = mdss_mdp_get_ad(mfd);
+ if (!ad || ad->cfg.mode == MDSS_AD_MODE_AUTO_BL)
+ return -EINVAL;
+
+ pr_debug("backlight level changed (%d), trigger update to AD",
+ mfd->bl_level);
input.mode = ad->cfg.mode;
if (MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, MDSS_AD_INPUT_AMBIENT))
input.in.amb_light = ad->ad_data;
@@ -2762,6 +2792,8 @@
{
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
+ int lin_ret = -1, inv_ret = -1, ret = 0;
+ u32 ratio_temp, shift = 0;
ad = mdss_mdp_get_ad(mfd);
if (!ad)
@@ -2771,6 +2803,29 @@
if (init_cfg->ops & MDP_PP_AD_INIT) {
memcpy(&ad->init, &init_cfg->params.init,
sizeof(struct mdss_ad_init));
+ if (init_cfg->params.init.bl_lin_len == AD_BL_LIN_LEN) {
+ lin_ret = copy_from_user(&ad->bl_lin,
+ init_cfg->params.init.bl_lin,
+ AD_BL_LIN_LEN * sizeof(uint32_t));
+ inv_ret = copy_from_user(&ad->bl_lin_inv,
+ init_cfg->params.init.bl_lin_inv,
+ AD_BL_LIN_LEN * sizeof(uint32_t));
+ if (lin_ret || inv_ret)
+ ret = -ENOMEM;
+ ratio_temp = mfd->panel_info->bl_max / AD_BL_LIN_LEN;
+ while (ratio_temp > 0) {
+ ratio_temp = ratio_temp >> 1;
+ shift++;
+ }
+ ad->bl_bright_shift = shift;
+ } else if (init_cfg->params.init.bl_lin_len) {
+ ret = -EINVAL;
+ }
+ if (!lin_ret && !inv_ret)
+ ad->state |= PP_AD_STATE_BL_LIN;
+ else
+ ad->state &= !PP_AD_STATE_BL_LIN;
+
ad->sts |= PP_AD_STS_DIRTY_INIT;
} else if (init_cfg->ops & MDP_PP_AD_CFG) {
memcpy(&ad->cfg, &init_cfg->params.cfg,
@@ -2783,17 +2838,21 @@
ad->sts |= PP_AD_STS_DIRTY_CFG;
}
- if (init_cfg->ops & MDP_PP_OPS_DISABLE) {
+ if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
ad->sts &= ~PP_STS_ENABLE;
+ mutex_unlock(&ad->lock);
+ cancel_work_sync(&ad->calc_work);
+ mutex_lock(&ad->lock);
ad->mfd = NULL;
- } else if (init_cfg->ops & MDP_PP_OPS_ENABLE) {
+ } else if (!ret && (init_cfg->ops & MDP_PP_OPS_ENABLE)) {
ad->sts |= PP_STS_ENABLE;
ad->mfd = mfd;
}
mutex_unlock(&ad->lock);
ctl = mfd_to_ctl(mfd);
- mdss_mdp_pp_setup(ctl);
- return 0;
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
+ return ret;
}
int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
@@ -2801,14 +2860,16 @@
int ret = 0;
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
+ u32 bl;
ad = mdss_mdp_get_ad(mfd);
if (!ad)
return -EINVAL;
mutex_lock(&ad->lock);
- if (!PP_AD_STATE_IS_INITCFG(ad->state) &&
- !PP_AD_STS_IS_DIRTY(ad->sts)) {
+ if ((!PP_AD_STATE_IS_INITCFG(ad->state) &&
+ !PP_AD_STS_IS_DIRTY(ad->sts)) &&
+ !input->mode == MDSS_AD_MODE_CALIB) {
pr_warn("AD not initialized or configured.");
ret = -EPERM;
goto error;
@@ -2841,6 +2902,25 @@
ad->sts |= PP_AD_STS_DIRTY_VSYNC;
ad->sts |= PP_AD_STS_DIRTY_DATA;
break;
+ case MDSS_AD_MODE_CALIB:
+ wait = 0;
+ if (mfd->calib_mode) {
+ bl = input->in.calib_bl;
+ if (bl >= AD_BL_LIN_LEN) {
+ pr_warn("calib_bl 255 max!");
+ break;
+ }
+ mutex_unlock(&ad->lock);
+ mutex_lock(&mfd->bl_lock);
+ MDSS_BRIGHT_TO_BL(bl, bl, mfd->panel_info->bl_max,
+ MDSS_MAX_BL_BRIGHTNESS);
+ mdss_fb_set_backlight(mfd, bl);
+ mutex_unlock(&mfd->bl_lock);
+ mutex_lock(&ad->lock);
+ } else {
+ pr_warn("should be in calib mode");
+ }
+ break;
default:
pr_warn("invalid default %d", input->mode);
ret = -EINVAL;
@@ -2992,7 +3072,7 @@
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
char __iomem *base;
- u32 bypass = MDSS_PP_AD_BYPASS_DEF;
+ u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
ad = mdss_mdp_get_ad(mfd);
if (!ad)
@@ -3008,9 +3088,7 @@
ad->state);
}
if (!PP_AD_STS_IS_DIRTY(ad->sts) &&
- (ad->sts & PP_AD_STS_DIRTY_DATA ||
- (ad->state & PP_AD_STATE_RUN &&
- (ad->cfg.mode == MDSS_AD_MODE_AUTO_STR)))) {
+ (ad->sts & PP_AD_STS_DIRTY_DATA)) {
/*
* Write inputs to regs when the data has been updated or
* Assertive Display is up and running as long as there are
@@ -3018,12 +3096,22 @@
*/
ad->sts &= ~PP_AD_STS_DIRTY_DATA;
ad->state |= PP_AD_STATE_DATA;
- if (mfd->bl_level != ad->last_bl) {
- ad->last_bl = mfd->bl_level;
- ad->calc_itr = ad->cfg.stab_itr;
- ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ bl = 0;
+ if (MDSS_AD_RUNNING_AUTO_STR(ad) || ad->last_bl == 0) {
+ mutex_lock(&mfd->bl_lock);
+ bl = mfd->bl_level;
+ if (bl != ad->last_bl) {
+ ad->last_bl = bl;
+ ad->calc_itr = ad->cfg.stab_itr;
+ ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ }
+ if (ad->state & PP_AD_STATE_BL_LIN) {
+ bl = ad->bl_lin[bl >> ad->bl_bright_shift];
+ bl = bl << ad->bl_bright_shift;
+ }
+ mutex_unlock(&mfd->bl_lock);
}
- pp_ad_input_write(ad, mfd->bl_level);
+ pp_ad_input_write(ad, bl);
}
if (ad->sts & PP_AD_STS_DIRTY_CFG) {
@@ -3050,14 +3138,32 @@
ad->state |= PP_AD_STATE_RUN;
mutex_lock(&mfd->bl_lock);
mfd->mdp.update_ad_input = pp_update_ad_input;
+ mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
mutex_unlock(&mfd->bl_lock);
} else {
if (ad->state & PP_AD_STATE_RUN) {
ret = 1;
+ /* Clear state and regs when going to off state*/
+ ad->sts = 0;
ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ ad->state &= !PP_AD_STATE_INIT;
+ ad->state &= !PP_AD_STATE_CFG;
+ ad->state &= !PP_AD_STATE_DATA;
+ ad->state &= !PP_AD_STATE_BL_LIN;
+ ad->bl_bright_shift = 0;
+ ad->ad_data = 0;
+ ad->ad_data_mode = 0;
+ ad->calc_itr = 0;
+ memset(&ad->bl_lin, 0, sizeof(uint32_t) *
+ AD_BL_LIN_LEN);
+ memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
+ AD_BL_LIN_LEN);
+ memset(&ad->init, 0, sizeof(struct mdss_ad_init));
+ memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
mutex_lock(&mfd->bl_lock);
mfd->mdp.update_ad_input = NULL;
+ mfd->ext_bl_ctrl = 0;
mutex_unlock(&mfd->bl_lock);
}
ad->state &= ~PP_AD_STATE_RUN;
@@ -3067,7 +3173,8 @@
if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
ad->sts &= ~PP_AD_STS_DIRTY_VSYNC;
- if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr) {
+ if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr &&
+ (ad->state & PP_AD_STATE_RUN)) {
ctl->add_vsync_handler(ctl, &ad->handle);
ad->state |= PP_AD_STATE_VSYNC;
} else if ((PP_AD_STATE_VSYNC & ad->state) &&
@@ -3092,11 +3199,18 @@
{
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
+ struct msm_fb_data_type *mfd;
u32 bl, calc_done = 0;
ad = container_of(work, struct mdss_ad_info, calc_work);
- ctl = mfd_to_ctl(ad->mfd);
mutex_lock(&ad->lock);
+ if (!ad->mfd || !(ad->sts & PP_STS_ENABLE)) {
+ mutex_unlock(&ad->lock);
+ return;
+ }
+ mfd = ad->mfd;
+ ctl = mfd_to_ctl(ad->mfd);
+
if (PP_AD_STATE_RUN & ad->state) {
/* Kick off calculation */
ad->calc_itr--;
@@ -3115,6 +3229,13 @@
if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
bl = 0xFFFF & readl_relaxed(ad->base +
MDSS_MDP_REG_AD_BL_OUT);
+ if (ad->state & PP_AD_STATE_BL_LIN) {
+ bl = bl >> ad->bl_bright_shift;
+ bl = min_t(u32, bl,
+ MDSS_MAX_BL_BRIGHTNESS);
+ bl = ad->bl_lin_inv[bl];
+ bl = bl << ad->bl_bright_shift;
+ }
pr_debug("calc bl = %d", bl);
ad->last_str |= bl << 16;
mutex_lock(&ad->mfd->bl_lock);
@@ -3135,9 +3256,12 @@
ctl->remove_vsync_handler(ctl, &ad->handle);
}
mutex_unlock(&ad->lock);
- mutex_lock(&ad->mfd->lock);
+ mutex_lock(&mfd->lock);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + ad->num));
- mutex_unlock(&ad->mfd->lock);
+ mutex_unlock(&mfd->lock);
+
+ /* Trigger update notify to wake up those waiting for display updates */
+ mdss_fb_update_notify_update(mfd);
}
#define PP_AD_LUT_LEN 33
@@ -3181,3 +3305,96 @@
}
return rc;
}
+
+static int is_valid_calib_addr(void *addr)
+{
+ int ret = 0;
+ unsigned int ptr;
+ ptr = (unsigned int) addr;
+ /* if request is outside the MDP reg-map or is not aligned 4 */
+ if (ptr == 0x0 || ptr > 0x5138 || ptr % 0x4)
+ goto end;
+ if (ptr >= 0x100 && ptr <= 0x5138) {
+ /* if ptr is in dspp range */
+ if (ptr >= 0x4600 && ptr <= 0x5138) {
+ /* if ptr is in dspp0 range*/
+ if (ptr >= 0x4600 && ptr <= 0x4938)
+ ptr -= 0x4600;
+ /* if ptr is in dspp1 range */
+ else if (ptr >= 0x4a00 && ptr <= 0x4d38)
+ ptr -= 0x4a00;
+ /* if ptr is in dspp2 range */
+ else if (ptr >= 0x4e00 && ptr <= 0x5138)
+ ptr -= 0x4e00;
+ /* if ptr is in pcc plane rgb coeff.range */
+ if (ptr >= 0x30 && ptr <= 0xe8)
+ ret = 1;
+ /* if ptr is in ARLUT red range */
+ else if (ptr >= 0x2b0 && ptr <= 0x2b8)
+ ret = 1;
+ /* if ptr is in PA range */
+ else if (ptr >= 0x238 && ptr <= 0x244)
+ ret = 1;
+ /* if ptr is in ARLUT green range */
+ else if (ptr >= 0x2c0 && ptr <= 0x2c8)
+ ret = 1;
+ /* if ptr is in ARLUT blue range or
+ gamut map table range */
+ else if (ptr >= 0x2d0 && ptr <= 0x338)
+ ret = 1;
+ /* if ptr is dspp0,dspp1,dspp2 op mode
+ register */
+ else if (ptr == 0)
+ ret = 1;
+ } else if (ptr >= 0x600 && ptr <= 0x608)
+ ret = 1;
+ else if (ptr >= 0x400 && ptr <= 0x408)
+ ret = 1;
+ else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
+ (ptr == 0x1430) || (ptr == 0x1e38))
+ ret = 1;
+ else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
+ ret = 1;
+ else if (ptr >= 0x3220 && ptr <= 0x3228)
+ ret = 1;
+ else if (ptr >= 0x3200 || ptr == 0x100)
+ ret = 1;
+ }
+end:
+ return ret;
+}
+
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
+{
+ int ret = -1;
+ void *ptr = (void *) cfg->addr;
+
+ if (is_valid_calib_addr(ptr))
+ ret = 0;
+ else
+ return ret;
+ ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ if (cfg->ops & MDP_PP_OPS_READ) {
+ cfg->data = readl_relaxed(ptr);
+ *copyback = 1;
+ ret = 0;
+ } else if (cfg->ops & MDP_PP_OPS_WRITE) {
+ writel_relaxed(cfg->data, ptr);
+ ret = 0;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
+
+int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
+ struct mdss_calib_cfg *cfg)
+{
+ if (!mdss_pp_res || !mfd)
+ return -EINVAL;
+ mutex_lock(&mdss_pp_mutex);
+ mfd->calib_mode = cfg->calib_mask;
+ mutex_unlock(&mdss_pp_mutex);
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 5d9396a..f9894cc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -99,6 +99,7 @@
pr_debug("waiting for rot=%d to complete\n", rot->pipe->num);
mdss_mdp_display_wait4comp(ctl);
rot->busy = false;
+ mdss_mdp_smp_release(rot->pipe);
}
mutex_unlock(&rot->lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index d1f0c8d..74d2a9c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -27,7 +27,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_formats.h"
-
+#include "mdss_debug.h"
#define DEFAULT_FRAME_RATE 60
enum {
@@ -124,6 +124,7 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr)
{
+ struct mdss_data_type *mdata = ptr;
u32 isr, mask, hist_isr, hist_mask;
@@ -172,17 +173,25 @@
if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
- if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
+ }
- if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0);
+ }
- if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1);
+ }
- if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
+ }
if (isr & MDSS_MDP_INTR_WB_0_DONE)
mdss_mdp_intr_done(MDP_INTR_WB_0);
@@ -225,7 +234,6 @@
struct mdss_mdp_format_params *fmt,
struct mdss_mdp_plane_sizes *ps)
{
- u32 stride_off;
if (fmt->is_yuv) {
ps->rau_cnt = DIV_ROUND_UP(w, 64);
ps->ystride[0] = 64 * 4;
@@ -238,6 +246,9 @@
ps->rau_h[1] = 4;
} else
ps->ystride[1] = 32 * 2;
+
+ /* account for both chroma components */
+ ps->ystride[1] <<= 1;
} else if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
ps->rau_cnt = DIV_ROUND_UP(w, 32);
ps->ystride[0] = 32 * 4 * fmt->bpp;
@@ -249,11 +260,14 @@
return -EINVAL;
}
- stride_off = DIV_ROUND_UP(ps->rau_cnt, 8);
- ps->ystride[0] = ps->ystride[0] * ps->rau_cnt + stride_off;
- ps->ystride[1] = ps->ystride[1] * ps->rau_cnt + stride_off;
+ ps->ystride[0] *= ps->rau_cnt;
+ ps->ystride[1] *= ps->rau_cnt;
ps->num_planes = 2;
+ pr_debug("BWC rau_cnt=%d strides={%d,%d} heights={%d,%d}\n",
+ ps->rau_cnt, ps->ystride[0], ps->ystride[1],
+ ps->rau_h[0], ps->rau_h[1]);
+
return 0;
}
@@ -262,7 +276,7 @@
{
struct mdss_mdp_format_params *fmt;
int i, rc;
- u32 bpp, ystride0_off, ystride1_off;
+ u32 bpp;
if (ps == NULL)
return -EINVAL;
@@ -277,17 +291,23 @@
memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
if (bwc_mode) {
+ u32 height, meta_size;
+
rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
if (rc)
return rc;
- ystride0_off = DIV_ROUND_UP(h, ps->rau_h[0]);
- ystride1_off = DIV_ROUND_UP(h, ps->rau_h[1]);
- ps->plane_size[0] = (ps->ystride[0] * ystride0_off) +
- (ps->ystride[1] * ystride1_off);
- ps->ystride[0] += ps->ystride[1];
+
+ height = DIV_ROUND_UP(h, ps->rau_h[0]);
+ meta_size = DIV_ROUND_UP(ps->rau_cnt, 8);
+ ps->ystride[1] += meta_size;
+ ps->ystride[0] += ps->ystride[1] + meta_size;
+ ps->plane_size[0] = ps->ystride[0] * height;
+
ps->ystride[1] = 2;
- ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] *
- (ystride0_off + ystride1_off);
+ ps->plane_size[1] = 2 * ps->rau_cnt * height;
+
+ pr_debug("BWC data stride=%d size=%d meta size=%d\n",
+ ps->ystride[0], ps->plane_size[0], ps->plane_size[1]);
} else {
if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
ps->num_planes = 1;
@@ -544,7 +564,8 @@
u32 pixel_total;
struct mdss_panel_info *panel_info = mfd->panel_info;
- if (panel_info->type == MIPI_VIDEO_PANEL) {
+ if ((panel_info->type == MIPI_VIDEO_PANEL) ||
+ (panel_info->type == MIPI_CMD_PANEL)) {
frame_rate = panel_info->mipi.frame_rate;
} else {
pixel_total = (panel_info->lcdc.h_back_porch +
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 1f8244d..0bb68f9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -251,8 +251,8 @@
if (wb->secure_pipe)
mdss_mdp_pipe_destroy(wb->secure_pipe);
mutex_unlock(&wb->lock);
-
- mdp5_data->ctl->is_secure = false;
+ if (mdp5_data->ctl)
+ mdp5_data->ctl->is_secure = false;
mdp5_data->wb = NULL;
mutex_unlock(&mdss_mdp_wb_buf_lock);
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_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a1053fb..3f03725 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -361,7 +361,7 @@
pr_debug("%s:%u\n", __func__, __LINE__);
INIT_COMPLETION(mhl_ctrl->rgnd_done);
timeout = wait_for_completion_interruptible_timeout
- (&mhl_ctrl->rgnd_done, HZ/2);
+ (&mhl_ctrl->rgnd_done, HZ);
if (!timeout) {
/* most likely nothing plugged in USB */
/* USB HOST connected or already in USB mode */
@@ -377,6 +377,12 @@
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = data;
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+
+ enable_irq(client->irq);
+ /* wait for i2c interrupt line to be activated */
+ msleep(300);
if (id) {
/* When MHL cable is disconnected we get a sii8334
@@ -396,11 +402,16 @@
mhl_ctrl->notify_usb_online = usb_notify_cb;
if (!mhl_ctrl->disc_enabled) {
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
mhl_sii_reset_pin(mhl_ctrl, 0);
msleep(50);
mhl_sii_reset_pin(mhl_ctrl, 1);
- /* TX PR-guide requires a 100 ms wait here */
- msleep(100);
+ /* chipset PR recommends waiting for at least 100 ms
+ * the chipset needs longer to come out of D3 state.
+ */
+ msleep(300);
mhl_init_reg_settings(mhl_ctrl, true);
rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
} else {
@@ -690,8 +701,8 @@
MHL_SII_PAGE3_WR(0x3C, 0x80);
- if (mhl_ctrl->cur_state != POWER_STATE_D3)
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT6 | BIT5 | BIT4, BIT4);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL,
+ (BIT6 | BIT5 | BIT4), (BIT6 | BIT4));
/* Enable Auto Soft RESET */
MHL_SII_REG_NAME_WR(REG_SRST, 0x084);
@@ -858,11 +869,6 @@
static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- unsigned long flags;
-
- spin_lock_irqsave(&mhl_ctrl->lock, flags);
- mhl_ctrl->dwnstream_hpd &= ~BIT6;
- spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
/* disabling Tx termination */
MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
@@ -870,7 +876,7 @@
mhl_msc_clear(mhl_ctrl);
}
-static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
+static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
{
uint8_t rgnd_imp;
struct i2c_client *client = mhl_ctrl->i2c_handle;
@@ -967,12 +973,12 @@
if ((0x00 == status) &&\
(mhl_ctrl->cur_state == POWER_STATE_D3)) {
- pr_err("%s: invalid intr\n", __func__);
+ pr_warn("%s: invalid intr\n", __func__);
return 0;
}
if (0xFF == status) {
- pr_debug("%s: invalid intr 0xff\n", __func__);
+ pr_warn("%s: invalid intr 0xff\n", __func__);
MHL_SII_REG_NAME_WR(REG_INTR4, status);
return 0;
}
@@ -999,13 +1005,14 @@
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
- return -EACCES;
+ return 0;
}
if (status & BIT5) {
/* clr intr - reg int4 */
pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
(int)status);
+ mhl_ctrl->mhl_det_discon = true;
reg = MHL_SII_REG_NAME_RD(REG_INTR4);
MHL_SII_REG_NAME_WR(REG_INTR4, reg);
@@ -1013,7 +1020,7 @@
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
- return -EACCES;
+ return 0;
}
if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
@@ -1054,6 +1061,32 @@
MHL_SII_REG_NAME_WR(REG_INTR5, intr_5_stat);
}
+static void mhl_tx_down(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+ uint8_t reg;
+
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+
+ reg = MHL_SII_REG_NAME_RD(REG_INTR1);
+ MHL_SII_REG_NAME_WR(REG_INTR1, reg);
+
+ reg = MHL_SII_REG_NAME_RD(REG_INTR4);
+ MHL_SII_REG_NAME_WR(REG_INTR4, reg);
+
+ /* disable INTR1 and INTR4 */
+ MHL_SII_REG_NAME_MOD(REG_INTR1_MASK, BIT6, 0x0);
+ MHL_SII_REG_NAME_MOD(REG_INTR4_MASK,
+ (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6), 0x0);
+
+ MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ pr_debug("%s: disabled\n", __func__);
+ disable_irq_nosync(client->irq);
+}
static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
@@ -1085,20 +1118,24 @@
spin_lock_irqsave(&mhl_ctrl->lock, flags);
t = mhl_ctrl->dwnstream_hpd;
+ pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+ __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
if (BIT6 & (cbus_stat ^ t)) {
u8 status = cbus_stat & BIT6;
mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
- if (!status) {
- MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
- spin_lock_irqsave(&mhl_ctrl->lock, flags);
- mhl_ctrl->tx_powered_off = true;
- spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ if (!status && mhl_ctrl->mhl_det_discon) {
+ pr_debug("%s:%u: power_down\n",
+ __func__, __LINE__);
+ mhl_tx_down(mhl_ctrl);
}
spin_lock_irqsave(&mhl_ctrl->lock, flags);
mhl_ctrl->dwnstream_hpd = cbus_stat;
+ pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+ __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ mhl_ctrl->mhl_det_discon = false;
}
}
}
@@ -1252,6 +1289,7 @@
uint8_t cmd_data = 0x0;
int msc_msg_recved = 0;
int rc = -1;
+ unsigned long flags;
struct i2c_client *client = mhl_ctrl->i2c_handle;
regval = MHL_SII_REG_NAME_RD(REG_CBUS_INTR_STATUS);
@@ -1292,6 +1330,14 @@
intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_0);
MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_0, intr);
mhl_msc_recv_set_int(mhl_ctrl, 0, intr);
+ if (intr & MHL_INT_DCAP_CHG) {
+ /* No need to go to low power mode */
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = 0x00;
+ pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+ __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_1);
@@ -1337,8 +1383,18 @@
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
+ unsigned long flags;
+
pr_debug("%s: Getting Interrupts\n", __func__);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ if (mhl_ctrl->tx_powered_off) {
+ pr_warn("%s: powered off\n", __func__);
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
/*
* Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
* interrupts. In D3, we get only RGND
@@ -1398,6 +1454,8 @@
*/
mhl_init_reg_settings(mhl_ctrl, true);
switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+ pr_debug("%s:%u: power_down\n", __func__, __LINE__);
+ mhl_tx_down(mhl_ctrl);
return 0;
}
@@ -1875,6 +1933,72 @@
MODULE_DEVICE_TABLE(i2c, mhl_sii_i2c_id);
+#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
+static int mhl_i2c_suspend_sub(struct i2c_client *client)
+{
+ enable_irq_wake(client->irq);
+ disable_irq(client->irq);
+ return 0;
+}
+
+static int mhl_i2c_resume_sub(struct i2c_client *client)
+{
+ disable_irq_wake(client->irq);
+ enable_irq(client->irq);
+ return 0;
+}
+#endif /* defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP) */
+
+#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP)
+static int mhl_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+ if (!client)
+ return -ENODEV;
+ pr_debug("%s: mhl suspend\n", __func__);
+ return mhl_i2c_suspend_sub(client);
+}
+
+static int mhl_i2c_resume(struct i2c_client *client)
+{
+ if (!client)
+ return -ENODEV;
+ pr_debug("%s: mhl resume\n", __func__);
+ return mhl_i2c_resume_sub(client);
+}
+#else
+#define mhl_i2c_suspend NULL
+#define mhl_i2c_resume NULL
+#endif /* defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP) */
+
+#ifdef CONFIG_PM_SLEEP
+static int mhl_i2c_pm_suspend(struct device *dev)
+{
+ struct i2c_client *client =
+ container_of(dev, struct i2c_client, dev);
+
+ if (!client)
+ return -ENODEV;
+ pr_debug("%s: mhl pm suspend\n", __func__);
+ return mhl_i2c_suspend_sub(client);
+
+}
+
+static int mhl_i2c_pm_resume(struct device *dev)
+{
+ struct i2c_client *client =
+ container_of(dev, struct i2c_client, dev);
+
+ if (!client)
+ return -ENODEV;
+ pr_debug("%s: mhl pm resume\n", __func__);
+ return mhl_i2c_resume_sub(client);
+}
+
+static const struct dev_pm_ops mhl_i2c_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mhl_i2c_pm_suspend, mhl_i2c_pm_resume)
+};
+#endif /* CONFIG_PM_SLEEP */
+
static struct of_device_id mhl_match_table[] = {
{.compatible = COMPATIBLE_NAME,},
{ },
@@ -1885,9 +2009,16 @@
.name = MHL_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = mhl_match_table,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &mhl_i2c_pm_ops,
+#endif /* CONFIG_PM_SLEEP */
},
.probe = mhl_i2c_probe,
.remove = mhl_i2c_remove,
+#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP)
+ .suspend = mhl_i2c_suspend,
+ .resume = mhl_i2c_resume,
+#endif /* defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP) */
.id_table = mhl_sii_i2c_id,
};
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index cbfeafc..096f777 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -70,6 +70,7 @@
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
+void set_power_on_alarm(long secs);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 3f35dd9..298fc9a 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -7,6 +7,7 @@
OST_ENTITY_TRACE_PRINTK = 0x02,
OST_ENTITY_TRACE_MARKER = 0x04,
OST_ENTITY_DEV_NODE = 0x08,
+ OST_ENTITY_DIAG = 0xEE,
OST_ENTITY_QVIEW = 0xFE,
OST_ENTITY_MAX = 0xFF,
};
diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h
index a379d38..af8c332 100644
--- a/include/linux/input/ft5x06_ts.h
+++ b/include/linux/input/ft5x06_ts.h
@@ -3,7 +3,7 @@
* FocalTech ft5x06 TouchScreen driver header file.
*
* Copyright (c) 2010 Focal tech Ltd.
- * 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
@@ -18,12 +18,28 @@
#ifndef __LINUX_FT5X06_TS_H__
#define __LINUX_FT5X06_TS_H__
+#define FT5X06_ID 0x55
+#define FT5X16_ID 0x0A
+#define FT5X36_ID 0x14
+#define FT6X06_ID 0x06
+
struct ft5x06_ts_platform_data {
- unsigned long irqflags;
+ u32 irqflags;
+ u32 irq_gpio;
+ u32 irq_gpio_flags;
+ u32 reset_gpio;
+ u32 reset_gpio_flags;
+ u32 family_id;
u32 x_max;
u32 y_max;
- u32 irq_gpio;
- u32 reset_gpio;
+ u32 x_min;
+ u32 y_min;
+ u32 panel_minx;
+ u32 panel_miny;
+ u32 panel_maxx;
+ u32 panel_maxy;
+ bool no_force_update;
+ bool i2c_pull_up;
int (*power_init) (bool);
int (*power_on) (bool);
};
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index f90f59e..73016d6 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,7 +35,6 @@
* struct synaptics_rmi4_platform_data - rmi4 platform data
* @x_flip: x flip flag
* @y_flip: y flip flag
- * @regulator_en: regulator enable flag
* @irq_gpio: attention interrupt gpio
* @irq_flags: flags used by the irq
* @reset_gpio: reset gpio
@@ -47,7 +46,6 @@
struct synaptics_rmi4_platform_data {
bool x_flip;
bool y_flip;
- bool regulator_en;
bool i2c_pull_up;
unsigned irq_gpio;
u32 irq_flags;
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index a19c0b6..7562166 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -37,6 +37,12 @@
* is considered empty(mV)
* @enable_fcc_learning: if set the driver will learn full charge
* capacity of the battery upon end of charge
+ * @min_fcc_learning_soc: minimum SOC as which CC counting for FCC
+ * learning can start
+ * @min_fcc_ocv_pc: minimum PC (lookup(OCV)) at which CC counting
+ * for FCC learning can start
+ * @max_fcc_learning_samples: Maximum number of FCC measurement cycles to be
+ * used for FCC update
* @normal_voltage_calc_ms: The period of soc calculation in ms when battery
* voltage higher than cutoff voltage
* @low_voltage_calc_ms: The period of soc calculation in ms when battery
@@ -66,6 +72,9 @@
unsigned int alarm_low_mv;
unsigned int alarm_high_mv;
int enable_fcc_learning;
+ int min_fcc_learning_soc;
+ int min_fcc_ocv_pc;
+ int max_fcc_learning_samples;
int shutdown_soc_valid_limit;
int ignore_shutdown_soc;
int adjust_soc_low_threshold;
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 0d1f49f..e688bd9 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -76,7 +76,8 @@
WCD9XXX_IRQ_EAR_PA_OCPL_FAULT,
WCD9XXX_IRQ_HPH_L_PA_STARTUP,
WCD9XXX_IRQ_HPH_R_PA_STARTUP,
- WCD9XXX_IRQ_EAR_PA_STARTUP,
+ WCD9320_IRQ_EAR_PA_STARTUP,
+ WCD9306_IRQ_MBHC_JACK_SWITCH = WCD9320_IRQ_EAR_PA_STARTUP,
WCD9310_NUM_IRQS,
WCD9XXX_IRQ_RESERVED_0 = WCD9310_NUM_IRQS,
WCD9XXX_IRQ_RESERVED_1,
@@ -85,7 +86,7 @@
WCD9XXX_IRQ_MAD_BEACON,
WCD9XXX_IRQ_MAD_ULTRASOUND,
WCD9XXX_IRQ_SPEAKER_CLIPPING,
- WCD9XXX_IRQ_MBHC_JACK_SWITCH,
+ WCD9320_IRQ_MBHC_JACK_SWITCH,
WCD9XXX_IRQ_VBAT_MONITOR_ATTACK,
WCD9XXX_IRQ_VBAT_MONITOR_RELEASE,
WCD9XXX_NUM_IRQS,
@@ -153,6 +154,13 @@
#define WCD9XXX_CH(xport, xshift) \
{.port = xport, .shift = xshift}
+enum wcd9xxx_chipid_major {
+ TABLA_MAJOR = cpu_to_le16(0x100),
+ SITAR_MAJOR = cpu_to_le16(0x101),
+ TAIKO_MAJOR = cpu_to_le16(0x102),
+ TAPAN_MAJOR = cpu_to_le16(0x103),
+};
+
struct wcd9xxx_codec_type {
u16 id_major;
u16 id_minor;
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index f04bf80..7297ff3 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -162,6 +162,7 @@
spinlock_t lock;
bool tx_powered_off;
uint8_t dwnstream_hpd;
+ bool mhl_det_discon;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9a4e61d..2cb297e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/mmc/core.h>
#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
struct mmc_cid {
unsigned int manfid;
@@ -173,7 +174,8 @@
wide_bus:1,
high_power:1,
high_speed:1,
- disable_cd:1;
+ disable_cd:1,
+ async_intr_sup:1;
};
struct sdio_cis {
@@ -276,7 +278,6 @@
* percentage of sectors that should issue check for
* BKOPS need
* @bkops_stats: BKOPS statistics
- * @poll_for_completion: Poll on BKOPS completion
* @cancel_delayed_work: A flag to indicate if the delayed work
* should be cancelled
* @sectors_changed: number of sectors written or
@@ -294,10 +295,6 @@
* is idle.
*/
#define MMC_IDLE_BKOPS_TIME_MS 200
- struct work_struct poll_for_completion;
-/* Polling timeout and interval for waiting on non-blocking BKOPs completion */
-#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS (4 * 60 * 1000) /* in ms */
-#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
bool cancel_delayed_work;
unsigned int sectors_changed;
/*
@@ -388,6 +385,8 @@
struct device_attribute rpm_attrib;
unsigned int idle_timeout;
+ struct notifier_block reboot_notify;
+ bool issue_long_pon;
};
/*
@@ -608,6 +607,7 @@
void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *);
int (*resume)(struct mmc_card *);
+ void (*shutdown)(struct mmc_card *);
};
extern int mmc_register_driver(struct mmc_driver *);
@@ -619,4 +619,5 @@
struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
extern void mmc_blk_disable_wr_packing(struct mmc_queue *mq);
+extern int mmc_send_long_pon(struct mmc_card *card);
#endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 995f8a2..f548721 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -146,6 +146,7 @@
extern int mmc_stop_bkops(struct mmc_card *);
extern int mmc_read_bkops_status(struct mmc_card *);
+extern bool mmc_card_is_prog_state(struct mmc_card *);
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 48be19a..dbafdfc 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -279,6 +279,7 @@
#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */
#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */
+#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
#define MMC_CAP2_PACKED_RD (1 << 12) /* Allow packed read */
#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */
@@ -292,6 +293,8 @@
#define MMC_CAP2_STOP_REQUEST (1 << 18) /* Allow stop ongoing request */
/* Use runtime PM framework provided by MMC core */
#define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
+/* Allows Asynchronous SDIO irq while card is in 4-bit mode */
+#define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 20)
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -414,6 +417,7 @@
};
extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
+extern bool mmc_host_may_gate_card(struct mmc_card *);
extern int mmc_add_host(struct mmc_host *);
extern void mmc_remove_host(struct mmc_host *);
extern void mmc_free_host(struct mmc_host *);
diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
index 58e52d4..961a4e1 100644
--- a/include/linux/mmc/sdio.h
+++ b/include/linux/mmc/sdio.h
@@ -162,6 +162,10 @@
#define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT)
+
+#define SDIO_CCCR_INTERRUPT_EXTENSION 0x16
+#define SDIO_SUPPORT_ASYNC_INTR (1<<0)
+#define SDIO_ENABLE_ASYNC_INTR (1<<1)
/*
* Function Basic Registers (FBR)
*/
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_mdp.h b/include/linux/msm_mdp.h
index e4df414..18921a0 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -50,7 +50,7 @@
#define MSMFB_HISTOGRAM_START _IOR(MSMFB_IOCTL_MAGIC, 144, \
struct mdp_histogram_start_req)
#define MSMFB_HISTOGRAM_STOP _IOR(MSMFB_IOCTL_MAGIC, 145, unsigned int)
-#define MSMFB_NOTIFY_UPDATE _IOW(MSMFB_IOCTL_MAGIC, 146, unsigned int)
+#define MSMFB_NOTIFY_UPDATE _IOWR(MSMFB_IOCTL_MAGIC, 146, unsigned int)
#define MSMFB_OVERLAY_3D _IOWR(MSMFB_IOCTL_MAGIC, 147, \
struct msmfb_overlay_3d)
@@ -78,6 +78,7 @@
#define MSMFB_METADATA_GET _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata)
#define MSMFB_WRITEBACK_SET_MIRRORING_HINT _IOW(MSMFB_IOCTL_MAGIC, 167, \
unsigned int)
+#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
@@ -89,6 +90,12 @@
};
enum {
+ NOTIFY_TYPE_NO_UPDATE,
+ NOTIFY_TYPE_SUSPEND,
+ NOTIFY_TYPE_UPDATE,
+};
+
+enum {
MDP_RGB_565, /* RGB 565 planer */
MDP_XRGB_8888, /* RGB 888 padded */
MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planer w/ Cb is in MSB */
@@ -436,6 +443,31 @@
uint32_t *b;
};
+enum {
+ DISPLAY_MISR_EDP,
+ DISPLAY_MISR_DSI0,
+ DISPLAY_MISR_DSI1,
+ DISPLAY_MISR_HDMI,
+ DISPLAY_MISR_LCDC,
+ DISPLAY_MISR_ATV,
+ DISPLAY_MISR_DSI_CMD,
+ DISPLAY_MISR_MAX
+};
+
+enum {
+ MISR_OP_NONE,
+ MISR_OP_SFM,
+ MISR_OP_MFM,
+ MISR_OP_BM,
+ MISR_OP_MAX
+};
+
+struct mdp_misr {
+ uint32_t block_id;
+ uint32_t frame_count;
+ uint32_t crc_op_mode;
+ uint32_t crc_value[32];
+};
/*
@@ -574,10 +606,14 @@
uint32_t data;
};
+#define MDSS_MAX_BL_BRIGHTNESS 255
+#define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
+
#define MDSS_AD_MODE_AUTO_BL 0x0
#define MDSS_AD_MODE_AUTO_STR 0x1
#define MDSS_AD_MODE_TARG_STR 0x3
#define MDSS_AD_MODE_MAN_STR 0x7
+#define MDSS_AD_MODE_CALIB 0xF
#define MDP_PP_AD_INIT 0x10
#define MDP_PP_AD_CFG 0x20
@@ -600,8 +636,13 @@
uint16_t frame_h;
uint8_t logo_v;
uint8_t logo_h;
+ uint32_t bl_lin_len;
+ uint32_t *bl_lin;
+ uint32_t *bl_lin_inv;
};
+#define MDSS_AD_BL_CTRL_MODE_EN 1
+#define MDSS_AD_BL_CTRL_MODE_DIS 0
struct mdss_ad_cfg {
uint32_t mode;
uint32_t al_calib_lut[33];
@@ -614,6 +655,7 @@
uint8_t strength_limit;
uint8_t t_filter_recursion;
uint16_t stab_itr;
+ uint32_t bl_ctrl_mode;
};
/* ops uses standard MDP_PP_* flags */
@@ -631,10 +673,17 @@
union {
uint32_t amb_light;
uint32_t strength;
+ uint32_t calib_bl;
} in;
uint32_t output;
};
+#define MDSS_CALIB_MODE_BL 0x1
+struct mdss_calib_cfg {
+ uint32_t ops;
+ uint32_t calib_mask;
+};
+
enum {
mdp_op_pcc_cfg,
mdp_op_csc_cfg,
@@ -647,6 +696,7 @@
mdp_op_calib_cfg,
mdp_op_ad_cfg,
mdp_op_ad_input,
+ mdp_op_calib_mode,
mdp_op_max,
};
@@ -672,6 +722,7 @@
struct mdp_gamut_cfg_data gamut_cfg_data;
struct mdp_calib_config_data calib_cfg;
struct mdss_ad_init_cfg ad_init_cfg;
+ struct mdss_calib_cfg mdss_calib_cfg;
struct mdss_ad_input ad_input;
} data;
};
@@ -684,6 +735,7 @@
metadata_op_vic,
metadata_op_wb_format,
metadata_op_get_caps,
+ metadata_op_crc,
metadata_op_max
};
@@ -708,6 +760,7 @@
uint32_t op;
uint32_t flags;
union {
+ struct mdp_misr misr_request;
struct mdp_blend_cfg blend_cfg;
struct mdp_mixer_cfg mixer_cfg;
uint32_t panel_frame_rate;
@@ -726,6 +779,12 @@
int *rel_fen_fd;
};
+struct mdp_async_blit_req_list {
+ struct mdp_buf_sync sync;
+ uint32_t count;
+ struct mdp_blit_req req[];
+};
+
#define MDP_DISPLAY_COMMIT_OVERLAY 1
struct mdp_buf_fence {
uint32_t flags;
diff --git a/include/linux/netfilter_ipv4/ipt_NATTYPE.h b/include/linux/netfilter_ipv4/ipt_NATTYPE.h
index 88311c9..594b62a 100644
--- a/include/linux/netfilter_ipv4/ipt_NATTYPE.h
+++ b/include/linux/netfilter_ipv4/ipt_NATTYPE.h
@@ -21,7 +21,8 @@
u_int16_t type;
};
-extern bool nattype_refresh_timer(unsigned long nattype);
+extern bool nattype_refresh_timer(unsigned long nattype,
+unsigned long timeout_value);
#endif /*_IPT_NATTYPE_H_target*/
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index d179eab..e8e932e 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.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
@@ -54,7 +54,7 @@
struct spmi_controller {
struct device dev;
unsigned int nr;
- struct list_head list;
+ struct completion dev_released;
int (*cmd)(struct spmi_controller *, u8 opcode, u8 sid);
int (*read_cmd)(struct spmi_controller *,
u8 opcode, u8 sid, u16 addr, u8 bc, u8 *buf);
diff --git a/include/linux/sync.h b/include/linux/sync.h
index 31ba6ec..f4ac10e 100644
--- a/include/linux/sync.h
+++ b/include/linux/sync.h
@@ -101,7 +101,7 @@
struct sync_timeline {
struct kref kref;
const struct sync_timeline_ops *ops;
- char name[32];
+ char name[64];
/* protected by child_list_lock */
bool destroyed;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 209062b..f9729c4 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -425,6 +425,7 @@
bool enable_hbm;
bool disable_park_mode;
bool consider_ipa_handshake;
+ bool ahb_async_bridge_bypass;
};
struct msm_usb_host_platform_data {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 323f1e7..c6da2c3 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1671,13 +1671,6 @@
/* MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
#define V4L2_CID_MPEG_MFC51_BASE (V4L2_CTRL_CLASS_MPEG | 0x1100)
-#define V4L2_CID_MPEG_QCOM_BASE (V4L2_CTRL_CLASS_MPEG | 0x2100)
-
-#define V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL (V4L2_CID_MPEG_QCOM_BASE + 0)
-enum v3l2_mpeg_qcom_perf_level {
- V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE = 0,
- V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO = 1,
-};
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0)
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1)
@@ -1851,9 +1844,11 @@
#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
enum v4l2_mpeg_vidc_perf_level {
- V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE = 0,
- V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO = 1,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL = 0,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE = 1,
+ V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO = 2,
};
+
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
(V4L2_CID_MPEG_MSM_VIDC_BASE+27)
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2a53114..2ba585e 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -34,6 +34,7 @@
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define HAVE_WCNSS_RX_BUFF_COUNT 1
struct device *wcnss_wlan_get_device(void);
struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -69,6 +70,7 @@
int wcnss_device_ready(void);
void wcnss_riva_dump_pmic_regs(void);
int wcnss_xo_auto_detect_enabled(void);
+u32 wcnss_get_wlan_rx_buff_count(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/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 47cf184..31798d6 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -184,6 +184,18 @@
uint16_t delay;
};
+struct msm_camera_i2c_array_write_config {
+ struct msm_camera_i2c_reg_setting conf_array;
+ uint16_t slave_addr;
+};
+
+struct msm_camera_i2c_read_config {
+ uint16_t slave_addr;
+ uint16_t reg_addr;
+ enum msm_camera_i2c_data_type data_type;
+ uint16_t *data;
+};
+
struct msm_camera_csid_vc_cfg {
uint8_t cid;
uint8_t dt;
@@ -320,7 +332,9 @@
enum msm_sensor_cfg_type_t {
CFG_SET_SLAVE_INFO,
+ CFG_SLAVE_READ_I2C,
CFG_WRITE_I2C_ARRAY,
+ CFG_SLAVE_WRITE_I2C_ARRAY,
CFG_WRITE_I2C_SEQ_ARRAY,
CFG_POWER_UP,
CFG_POWER_DOWN,
diff --git a/include/media/msmb_camera.h b/include/media/msmb_camera.h
index 21a1c44..388b308 100644
--- a/include/media/msmb_camera.h
+++ b/include/media/msmb_camera.h
@@ -14,6 +14,9 @@
#define MSM_CAM_V4L2_IOCTL_CMD_ACK \
_IOW('V', BASE_VIDIOC_PRIVATE + 32, struct v4l2_event)
+#define MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR \
+ _IOW('V', BASE_VIDIOC_PRIVATE + 33, struct v4l2_event)
+
#define QCAMERA_DEVICE_GROUP_ID 1
#define QCAMERA_VNODE_GROUP_ID 2
#define MSM_CAMERA_NAME "msm_camera"
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 3775ddd..25d528d7 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -161,12 +161,20 @@
ENABLE_STREAM_BUF_DIVERT,
DISABLE_STREAM_BUF_DIVERT,
UPDATE_STREAM_FRAMEDROP_PATTERN,
+ UPDATE_STREAM_AXI_CONFIG,
+};
+
+struct msm_vfe_axi_stream_cfg_update_info {
+ uint32_t stream_handle;
+ uint32_t output_format;
+ enum msm_vfe_frame_skip_pattern skip_pattern;
+ struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
};
struct msm_vfe_axi_stream_update_cmd {
- uint32_t stream_handle;
+ uint32_t num_streams;
enum msm_vfe_axi_stream_update_type update_type;
- enum msm_vfe_frame_skip_pattern skip_pattern;
+ struct msm_vfe_axi_stream_cfg_update_info update_info[MAX_NUM_STREAM];
};
enum msm_isp_stats_type {
@@ -317,6 +325,7 @@
uint32_t session_id;
uint32_t stream_id;
uint32_t handle;
+ uint32_t output_format;
int8_t buf_idx;
};
struct msm_isp_stats_event {
@@ -335,6 +344,8 @@
*which use monotonic clock
*/
struct timeval timestamp;
+ /* Monotonic timestamp since bootup */
+ struct timeval mono_timestamp;
/* if pix is a src frame_id is from camif */
uint32_t frame_id;
union {
@@ -362,6 +373,8 @@
#define V4L2_PIX_FMT_QGBRG12 v4l2_fourcc('Q', 'G', 'B', '2')
#define V4L2_PIX_FMT_QGRBG12 v4l2_fourcc('Q', 'G', 'R', '2')
#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2')
+#define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4')
+#define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1')
#define VIDIOC_MSM_VFE_REG_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 028e683..8984405 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -447,6 +447,7 @@
#endif
#endif
struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
+ struct snd_kcontrol *vol_kctl; /* volume controls */
};
struct snd_pcm {
@@ -1128,4 +1129,28 @@
unsigned long private_value,
struct snd_pcm_chmap **info_ret);
+/*
+ * PCM Volume control API
+ */
+/* array element of volume */
+struct snd_pcm_volume_elem {
+ int volume;
+};
+
+/* pp information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_volume {
+ struct snd_pcm *pcm; /* assigned PCM instance */
+ int stream; /* PLAYBACK or CAPTURE */
+ struct snd_kcontrol *kctl;
+ const struct snd_pcm_volume_elem *volume;
+ int max_length;
+ void *private_data; /* optional: private data pointer */
+};
+
+int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_volume_elem *volume,
+ int max_length,
+ unsigned long private_value,
+ struct snd_pcm_volume **info_ret);
+
#endif /* __SOUND_PCM_H */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 449694e..795bb99 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -54,6 +54,8 @@
int adm_connect_afe_port(int mode, int session_id, int port_id);
+void adm_ec_ref_rx_id(int port_id);
+
int adm_get_copp_id(int port_id);
void adm_set_multi_ch_map(char *channel_map);
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 1389b2a..2e4c7c1 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -197,6 +197,8 @@
enum afe_mad_type afe_port_get_mad_type(u16 port_id);
int afe_set_config(enum afe_config_type config_type, void *config_data,
int arg);
+void afe_clear_config(enum afe_config_type config);
+bool afe_has_config(enum afe_config_type config);
void afe_set_aanc_info(struct aanc_data *aanc_info);
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index e9ca91d..d7a01a0 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -124,6 +124,7 @@
int q6lsm_start(struct lsm_client *client, bool wait);
int q6lsm_stop(struct lsm_client *client, bool wait);
int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_snd_model_buf_free(struct lsm_client *client);
int q6lsm_close(struct lsm_client *client);
int q6lsm_register_sound_model(struct lsm_client *client,
enum lsm_detection_mode mode, u16 minkeyword,
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
index 909e1b9..f36e4d5 100644
--- a/include/trace/events/kmem.h
+++ b/include/trace/events/kmem.h
@@ -314,7 +314,7 @@
TP_ARGS(client_name, heap_name, len, mask, flags),
TP_STRUCT__entry(
- __field(const char *, client_name)
+ __array(char, client_name, 64)
__field(const char *, heap_name)
__field(size_t, len)
__field(unsigned int, mask)
@@ -322,7 +322,7 @@
),
TP_fast_assign(
- __entry->client_name = client_name;
+ strlcpy(__entry->client_name, client_name, 64);
__entry->heap_name = heap_name;
__entry->len = len;
__entry->mask = mask;
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/kernel/signal.c b/kernel/signal.c
index 17afcaf..7a06651 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -482,6 +482,9 @@
if (force_default || ka->sa.sa_handler != SIG_IGN)
ka->sa.sa_handler = SIG_DFL;
ka->sa.sa_flags = 0;
+#ifdef SA_RESTORER
+ ka->sa.sa_restorer = NULL;
+#endif
sigemptyset(&ka->sa.sa_mask);
ka++;
}
diff --git a/net/ipv4/netfilter/ipt_NATTYPE.c b/net/ipv4/netfilter/ipt_NATTYPE.c
index 2bb18ca..f181be4 100644
--- a/net/ipv4/netfilter/ipt_NATTYPE.c
+++ b/net/ipv4/netfilter/ipt_NATTYPE.c
@@ -58,6 +58,7 @@
struct ipt_nattype {
struct list_head list;
struct timer_list timeout;
+ unsigned long timeout_value;
unsigned char is_valid;
unsigned short proto; /* Protocol: TCP or UDP */
struct nf_nat_ipv4_range range; /* LAN side source information */
@@ -102,7 +103,7 @@
* nattype_refresh_timer()
* Refresh the timer for this object.
*/
-bool nattype_refresh_timer(unsigned long nat_type)
+bool nattype_refresh_timer(unsigned long nat_type, unsigned long timeout_value)
{
struct ipt_nattype *nte = (struct ipt_nattype *)nat_type;
if (!nte)
@@ -113,7 +114,8 @@
return false;
}
if (del_timer(&nte->timeout)) {
- nte->timeout.expires = jiffies + NATTYPE_TIMEOUT * HZ;
+ nte->timeout_value = timeout_value - jiffies;
+ nte->timeout.expires = timeout_value;
add_timer(&nte->timeout);
spin_unlock_bh(&nattype_lock);
return true;
@@ -222,7 +224,8 @@
* nattype_compare
* Compare two entries, return true if relevant fields are the same.
*/
-static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2)
+static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2,
+ const struct ipt_nattype_info *info)
{
/*
* Protocol compare.
@@ -261,19 +264,15 @@
}
/*
- * Destination compare
+ * Destination Comapre for Address Restricted Cone NAT.
*/
- if (n1->dest_addr != n2->dest_addr) {
+ if ((info->type == TYPE_ADDRESS_RESTRICTED) &&
+ (n1->dest_addr != n2->dest_addr)) {
DEBUGP("nattype_compare: dest_addr mismatch: %pI4:%pI4\n",
- &n1->dest_addr, &n2->dest_addr);
+ &n1->dest_addr, &n2->dest_addr);
return false;
}
- if (n1->dest_port != n2->dest_port) {
- DEBUGP("nattype_compare: dest_port mismatch: %d:%d\n",
- ntohs(n1->dest_port), ntohs(n2->dest_port));
- return false;
- }
return true;
}
@@ -316,6 +315,15 @@
}
/*
+ * Refresh the timer, if we fail, break
+ * out and forward fail as though we never
+ * found the entry.
+ */
+ if (!nattype_refresh_timer((unsigned long)nte,
+ jiffies + nte->timeout_value))
+ break;
+
+ /*
* Expand the ingress conntrack to include the reply as source
*/
DEBUGP("Expand ingress conntrack=%p, type=%d, src[%pI4:%d]\n",
@@ -344,11 +352,21 @@
enum ip_conntrack_info ctinfo;
const struct ipt_nattype_info *info = par->targinfo;
uint16_t nat_port;
+ enum ip_conntrack_dir dir;
+
if (par->hooknum != NF_INET_FORWARD)
return XT_CONTINUE;
/*
+ * Egress packet, create a new rule in our list. If conntrack does
+ * not have an entry, skip this packet.
+ */
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct)
+ return XT_CONTINUE;
+
+ /*
* Ingress packet, refresh the timer if we find an entry.
*/
if (info->mode == MODE_FORWARD_IN) {
@@ -366,7 +384,8 @@
* out and forward fail as though we never
* found the entry.
*/
- if (!nattype_refresh_timer((unsigned long)nte))
+ if (!nattype_refresh_timer((unsigned long)nte,
+ ct->timeout.expires))
break;
/*
* The entry is found and refreshed, the
@@ -382,15 +401,9 @@
return XT_CONTINUE;
}
- /*
- * Egress packet, create a new rule in our list. If conntrack does
- * not have an entry, skip this packet.
- */
- ct = nf_ct_get(skb, &ctinfo);
- if (!ct || (ctinfo == IP_CT_NEW && ctinfo == IP_CT_RELATED))
- return XT_CONTINUE;
+ dir = CTINFO2DIR(ctinfo);
- nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all;
+ nat_port = ct->tuplehash[!dir].tuple.dst.u.all;
/*
* Allocate a new entry
@@ -439,7 +452,7 @@
*/
spin_lock_bh(&nattype_lock);
list_for_each_entry(nte2, &nattype_list, list) {
- if (!nattype_compare(nte, nte2))
+ if (!nattype_compare(nte, nte2, info))
continue;
spin_unlock_bh(&nattype_lock);
/*
@@ -447,7 +460,9 @@
* entry as this one is timed out and will be removed
* from the list shortly.
*/
- if (!nattype_refresh_timer((unsigned long)nte2))
+ nte2->timeout_value = ct->timeout.expires - jiffies;
+ if (!nattype_refresh_timer((unsigned long)nte2,
+ ct->timeout.expires))
break;
/*
* Found and refreshed an existing entry. Its values
@@ -463,7 +478,8 @@
/*
* Add the new entry to the list.
*/
- nte->timeout.expires = jiffies + (NATTYPE_TIMEOUT * HZ);
+ nte->timeout_value = ct->timeout.expires - jiffies;
+ nte->timeout.expires = ct->timeout.expires;
add_timer(&nte->timeout);
list_add(&nte->list, &nattype_list);
ct->nattype_entry = (unsigned long)nte;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 13925ac..d7eafd5 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1101,7 +1101,7 @@
/* Refresh the NAT type entry. */
#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE)
- (void)nattype_refresh_timer(ct->nattype_entry);
+ (void)nattype_refresh_timer(ct->nattype_entry, ct->timeout.expires);
#endif
acct:
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index ca7e835..6239080 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1229,6 +1229,11 @@
ct->timeout.expires = jiffies + timeout * HZ;
add_timer(&ct->timeout);
+/* Refresh the NAT type entry. */
+#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE)
+ (void)nattype_refresh_timer(ct->nattype_entry, ct->timeout.expires);
+#endif
+
return 0;
}
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 2010c57..548d655 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -40,10 +40,7 @@
# force LANG to be set to en_US.UTF-8 to get consistent warnings.
allowed_warnings = set([
- "alignment.c:327",
- "mmu.c:602",
"return_address.c:62",
- "extents.c:2091",
])
# Capture the name of the object file, can find it.
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index d98e160..2e8d6f4 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1199,6 +1199,10 @@
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
pcm->streams[cidx].chmap_kctl = NULL;
}
+ if (pcm->streams[cidx].vol_kctl) {
+ snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl);
+ pcm->streams[cidx].vol_kctl = NULL;
+ }
}
unlock:
mutex_unlock(®ister_mutex);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e0ab899..06d617b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -31,6 +31,8 @@
#include <sound/pcm_params.h>
#include <sound/timer.h>
+#define STRING_LENGTH_OF_INT 12
+
/*
* fill ring buffer with silence
* runtime->silence_start: starting pointer to silence area
@@ -2444,6 +2446,23 @@
kfree(info);
}
+static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x2000;
+ return 0;
+}
+
+static void pcm_volume_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+ struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol);
+ info->pcm->streams[info->stream].vol_kctl = NULL;
+ kfree(info);
+}
+
/**
* snd_pcm_add_chmap_ctls - create channel-mapping control elements
* @pcm: the assigned PCM instance
@@ -2503,3 +2522,74 @@
return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
+
+/**
+ * snd_pcm_add_volume_ctls - create volume control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @max_length: the max length of the volume parameter of stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_volume instance if non-NULL
+ *
+ * Create volume control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_volume_elem *volume,
+ int max_length,
+ unsigned long private_value,
+ struct snd_pcm_volume **info_ret)
+{
+ struct snd_pcm_volume *info;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = pcm_volume_ctl_info,
+ };
+ int err;
+ int size;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pcm = pcm;
+ info->stream = stream;
+ info->volume = volume;
+ info->max_length = max_length;
+ size = sizeof("Playback ") + sizeof(" Volume") +
+ STRING_LENGTH_OF_INT*sizeof(char) + 1;
+ knew.name = kzalloc(size, GFP_KERNEL);
+ if (!knew.name) {
+ kfree(info);
+ return -ENOMEM;
+ }
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snprintf(knew.name, size, "%s %d %s",
+ "Playback", pcm->device, "Volume");
+ else
+ snprintf(knew.name, size, "%s %d %s",
+ "Capture", pcm->device, "Volume");
+ knew.device = pcm->device;
+ knew.count = pcm->streams[stream].substream_count;
+ knew.private_value = private_value;
+ info->kctl = snd_ctl_new1(&knew, info);
+ if (!info->kctl) {
+ kfree(info);
+ kfree(knew.name);
+ return -ENOMEM;
+ }
+ info->kctl->private_free = pcm_volume_ctl_private_free;
+ err = snd_ctl_add(pcm->card, info->kctl);
+ if (err < 0) {
+ kfree(info);
+ kfree(knew.name);
+ return -ENOMEM;
+ }
+ pcm->streams[stream].vol_kctl = info->kctl;
+ if (info_ret)
+ *info_ret = info;
+ kfree(knew.name);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 1a11997..0ba1ec5 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -540,7 +540,7 @@
struct device *dev)
{
struct msm8x10_wcd_pdata *pdata;
- int ret, i;
+ int ret = 0, i;
char **codec_supplies;
u32 num_of_supplies = 0;
@@ -616,7 +616,7 @@
0x00);
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
- 0x01, 0x01);
+ 0x01, 0x00);
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
@@ -1750,6 +1750,7 @@
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
+ {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
{"MIC BIAS External", NULL, "INT_LDO_H"},
};
@@ -2280,7 +2281,6 @@
/* Reduce LINE DAC bias to 70% */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
-
/* Disable TX7 internal biasing path which can cause leakage */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
@@ -2288,6 +2288,13 @@
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
+
+ /* ClassG fine tuning setting for 16 ohm HPH */
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 669f8e3..8ae6050 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -67,14 +67,12 @@
#define TAPAN_I2S_MASTER_MODE_MASK 0x08
#define TAPAN_MCLK_CLK_12P288MHZ 12288000
-#define TAPAN_MCLK_CLK_9P6HZ 9600000
+#define TAPAN_MCLK_CLK_9P6MHZ 9600000
#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
-#define TAPAN_MCLK_CLK_12P288MHZ 12288000
-#define TAPAN_MCLK_CLK_9P6HZ 9600000
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -1867,7 +1865,7 @@
release_firmware(fw);
break;
- case SND_SOC_DAPM_POST_PMD:
+ case SND_SOC_DAPM_PRE_PMD:
msleep(40);
snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
@@ -2339,12 +2337,11 @@
snd_soc_update_bits(codec,
TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
msleep(40);
- }
- if (w->shift == 5) {
snd_soc_update_bits(codec,
TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
ret |= tapan_codec_enable_anc(w, kcontrol, event);
}
+ break;
case SND_SOC_DAPM_POST_PMD:
ret = tapan_hph_pa_event(w, kcontrol, event);
break;
@@ -4271,9 +4268,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[] = {
@@ -4331,6 +4325,23 @@
snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
}
+static void tapan_update_reg_mclk_rate(struct wcd9xxx *wcd9xxx)
+{
+ struct snd_soc_codec *codec;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+ __func__, wcd9xxx->mclk_rate);
+
+ if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
+ snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
+ snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
+ 0x01);
+ } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
+ snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
+ }
+}
+
static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
/* Initialize current threshold to 350MA
* number of wait and run cycles to 4096
@@ -4401,26 +4412,29 @@
tapan_codec_reg_init_val[i].mask,
tapan_codec_reg_init_val[i].val);
}
-
-static int tapan_setup_irqs(struct tapan_priv *tapan)
+static void tapan_slim_interface_init_reg(struct snd_soc_codec *codec)
{
int i;
- int ret = 0;
- struct snd_soc_codec *codec = tapan->codec;
-
- ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
- tapan_slimbus_irq, "SLIMBUS Slave", tapan);
- if (ret) {
- pr_err("%s: Failed to request irq %d\n", __func__,
- WCD9XXX_IRQ_SLIMBUS);
- goto exit;
- }
for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
wcd9xxx_interface_reg_write(codec->control_data,
TAPAN_SLIM_PGD_PORT_INT_EN0 + i,
0xFF);
-exit:
+}
+
+static int tapan_setup_irqs(struct tapan_priv *tapan)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec = tapan->codec;
+
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ tapan_slimbus_irq, "SLIMBUS Slave", tapan);
+ if (ret)
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ WCD9XXX_IRQ_SLIMBUS);
+ else
+ tapan_slim_interface_init_reg(codec);
+
return ret;
}
@@ -4438,9 +4452,74 @@
}
EXPORT_SYMBOL_GPL(tapan_hs_detect);
+static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+ int ret = 0;
+ int rco_clk_rate;
+ struct snd_soc_codec *codec;
+ struct tapan_priv *tapan;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ tapan = snd_soc_codec_get_drvdata(codec);
+ mutex_lock(&codec->mutex);
+ WCD9XXX_BCL_LOCK(&tapan->resmgr);
+
+ if (codec->reg_def_copy) {
+ pr_debug("%s: Update ASOC cache", __func__);
+ kfree(codec->reg_cache);
+ codec->reg_cache = kmemdup(codec->reg_def_copy,
+ codec->reg_size, GFP_KERNEL);
+ if (!codec->reg_cache) {
+ pr_err("%s: Cache update failed!\n", __func__);
+ WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
+ mutex_unlock(&codec->mutex);
+ return -ENOMEM;
+ }
+ }
+
+ wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
+ if (spkr_drv_wrnd == 1)
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
+ WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
+
+ tapan_update_reg_defaults(codec);
+ tapan_update_reg_mclk_rate(wcd9xxx);
+ tapan_codec_init_reg(codec);
+ ret = tapan_handle_pdata(tapan);
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: bad pdata\n", __func__);
+
+ tapan_slim_interface_init_reg(codec);
+
+ wcd9xxx_mbhc_deinit(&tapan->mbhc);
+
+ if (TAPAN_IS_1_0(wcd9xxx->version))
+ rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
+
+ ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
+ WCD9XXX_MBHC_VERSION_TAPAN,
+ rco_clk_rate);
+ if (ret)
+ pr_err("%s: mbhc init failed %d\n", __func__, ret);
+ else
+ wcd9xxx_mbhc_start(&tapan->mbhc, tapan->mbhc.mbhc_cfg);
+ mutex_unlock(&codec->mutex);
+ return ret;
+}
+
static struct wcd9xxx_reg_address tapan_reg_address = {
};
+static int wcd9xxx_ssr_register(struct wcd9xxx *control,
+ int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+{
+ control->post_reset = post_reset_cb;
+ control->ssr_priv = priv;
+ return 0;
+}
+
static int tapan_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -4449,12 +4528,14 @@
struct wcd9xxx *wcd9xxx;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
- int i;
+ int i, rco_clk_rate;
void *ptr = NULL;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
+ wcd9xxx_ssr_register(control, tapan_post_reset_cb, (void *)codec);
+
dev_info(codec->dev, "%s()\n", __func__);
tapan = kzalloc(sizeof(struct tapan_priv), GFP_KERNEL);
@@ -4485,8 +4566,14 @@
return ret;
}
- ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAPAN);
+ if (TAPAN_IS_1_0(control->version))
+ rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
+
+ ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
+ WCD9XXX_MBHC_VERSION_TAPAN,
+ rco_clk_rate);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
return ret;
@@ -4502,17 +4589,7 @@
tapan->aux_l_gain = 0x1F;
tapan->aux_r_gain = 0x1F;
tapan_update_reg_defaults(codec);
-
- dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
- __func__, wcd9xxx->mclk_rate);
-
- if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
- snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
- snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
- 0x01);
- } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
- snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
- }
+ tapan_update_reg_mclk_rate(wcd9xxx);
tapan_codec_init_reg(codec);
ret = tapan_handle_pdata(tapan);
if (IS_ERR_VALUE(ret)) {
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index ab96baf..67c03d6 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -47,6 +47,8 @@
#define TAIKO_HPH_PA_SETTLE_COMP_ON 3000
#define TAIKO_HPH_PA_SETTLE_COMP_OFF 13000
+#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+
static atomic_t kp_taiko_priv;
static int spkr_drv_wrnd_param_set(const char *val,
const struct kernel_param *kp);
@@ -320,7 +322,7 @@
#define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
#define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
#define TAIKO_MCLK_CLK_12P288MHZ 12288000
-#define TAIKO_MCLK_CLK_9P6HZ 9600000
+#define TAIKO_MCLK_CLK_9P6MHZ 9600000
#define TAIKO_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FORMAT_S24_LE)
@@ -469,6 +471,8 @@
s32 dmic_1_2_clk_cnt;
s32 dmic_3_4_clk_cnt;
s32 dmic_5_6_clk_cnt;
+ s32 ldo_h_users;
+ s32 micb_2_users;
u32 anc_slot;
bool anc_func;
@@ -502,6 +506,9 @@
/* class h specific data */
struct wcd9xxx_clsh_cdc_data clsh_d;
+
+ int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event);
};
static const u32 comp_shift[] = {
@@ -2661,16 +2668,26 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
- if (taiko->mbhc_started &&
- taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
- micb_ctl_reg == TAIKO_A_MICB_2_CTL)
- wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
- WCD9XXX_COND_HPH_MIC,
- micb_ctl_reg, w->shift,
- false);
- else
+ if (taiko->mbhc_started && micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ if (++taiko->micb_2_users == 1) {
+ if (taiko->resmgr.pdata->
+ micbias.bias2_is_headset_only)
+ wcd9xxx_resmgr_add_cond_update_bits(
+ &taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, w->shift,
+ false);
+ else
+ snd_soc_update_bits(codec, micb_ctl_reg,
+ 1 << w->shift,
+ 1 << w->shift);
+ }
+ pr_debug("%s: micb_2_users %d\n", __func__,
+ taiko->micb_2_users);
+ } else {
snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
1 << w->shift);
+ }
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20000);
@@ -2678,15 +2695,27 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- if (taiko->mbhc_started &&
- taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
- micb_ctl_reg == TAIKO_A_MICB_2_CTL)
- wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
- WCD9XXX_COND_HPH_MIC,
- micb_ctl_reg, 7, false);
- else
+ if (taiko->mbhc_started && micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ if (--taiko->micb_2_users == 0) {
+ if (taiko->resmgr.pdata->
+ micbias.bias2_is_headset_only)
+ wcd9xxx_resmgr_rm_cond_update_bits(
+ &taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, 7, false);
+ else
+ snd_soc_update_bits(codec, micb_ctl_reg,
+ 1 << w->shift, 0);
+ }
+ pr_debug("%s: micb_2_users %d\n", __func__,
+ taiko->micb_2_users);
+ WARN(taiko->micb_2_users < 0,
+ "Unexpected micbias users %d\n",
+ taiko->micb_2_users);
+ } else {
snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
0);
+ }
/* Let MBHC module know so micbias switch to be off */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
@@ -2706,6 +2735,22 @@
return 0;
}
+/* called under codec_resource_lock acquisition */
+static int taiko_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable)
+{
+ int rc;
+
+ if (enable)
+ rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
+ DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+ else
+ rc = snd_soc_dapm_disable_pin(&codec->dapm,
+ DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+ if (!rc)
+ snd_soc_dapm_sync(&codec->dapm);
+ pr_debug("%s: leave ret %d\n", __func__, rc);
+ return rc;
+}
static void tx_hpf_corner_freq_callback(struct work_struct *work)
{
@@ -2937,18 +2982,65 @@
return 0;
}
-static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+/* called under codec_resource_lock acquisition */
+static int __taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: enter\n", __func__);
switch (event) {
- case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_PRE_PMU:
+ if (++priv->ldo_h_users == 1) {
+ wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 1 << 7,
+ 1 << 7);
+ wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ pr_debug("%s: ldo_h_users %d\n", __func__,
+ priv->ldo_h_users);
+ /* LDO enable requires 1ms to settle down */
+ usleep_range(1000, 1000);
+ }
+ break;
case SND_SOC_DAPM_POST_PMD:
- usleep_range(1000, 1000);
+ if (--priv->ldo_h_users == 0) {
+ wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 1 << 7,
+ 0);
+ wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ pr_debug("%s: ldo_h_users %d\n", __func__,
+ priv->ldo_h_users);
+ }
+ WARN(priv->ldo_h_users < 0, "Unexpected ldo_h users %d\n",
+ priv->ldo_h_users);
break;
}
+ pr_debug("%s: leave\n", __func__);
return 0;
}
+static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int rc;
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ WCD9XXX_BCL_LOCK(&priv->resmgr);
+ rc = __taiko_codec_enable_ldo_h(w, kcontrol, event);
+ WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+ return rc;
+}
+
static int taiko_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -3696,13 +3788,15 @@
{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX7 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP2", "IIR2", "IIR2"},
+
+ /* IIR1, IIR2 inputs to Second RX Mixer on RX1, RX2 and RX7 chains. */
{"RX1 MIX2 INP1", "IIR1", "IIR1"},
{"RX1 MIX2 INP2", "IIR1", "IIR1"},
{"RX2 MIX2 INP1", "IIR1", "IIR1"},
{"RX2 MIX2 INP2", "IIR1", "IIR1"},
{"RX7 MIX2 INP1", "IIR1", "IIR1"},
{"RX7 MIX2 INP2", "IIR1", "IIR1"},
- {"RX7 MIX1 INP2", "IIR2", "IIR2"},
{"RX1 MIX2 INP1", "IIR2", "IIR2"},
{"RX1 MIX2 INP2", "IIR2", "IIR2"},
{"RX2 MIX2 INP1", "IIR2", "IIR2"},
@@ -3780,6 +3874,13 @@
{"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP1 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP1 MUX", "RX7", "SLIM RX7"},
{"IIR2", NULL, "IIR2 INP1 MUX"},
{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -3792,6 +3893,13 @@
{"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
{"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -3804,7 +3912,7 @@
{"MIC BIAS3 Internal2", NULL, "LDO_H"},
{"MIC BIAS3 External", NULL, "LDO_H"},
{"MIC BIAS4 External", NULL, "LDO_H"},
-
+ {DAPM_MICBIAS2_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
};
static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -5159,8 +5267,17 @@
SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
0),
- SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
- taiko_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("LDO_H", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_ldo_h,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /*
+ * DAPM 'LDO_H Standalone' is to be powered by mbhc driver after
+ * acquring codec_resource lock.
+ * So call __taiko_codec_enable_ldo_h instead and avoid deadlock.
+ */
+ SND_SOC_DAPM_SUPPLY("LDO_H Standalone", SND_SOC_NOPM, 7, 0,
+ __taiko_codec_enable_ldo_h,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
taiko_config_compander, SND_SOC_DAPM_PRE_PMU |
@@ -5265,6 +5382,10 @@
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_EXTERNAL_STANDALONE, SND_SOC_NOPM,
+ 7, 0, taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
taiko_codec_enable_micbias,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
@@ -5376,10 +5497,10 @@
/* Sidetone */
SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
- SND_SOC_DAPM_PGA("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
- SND_SOC_DAPM_PGA("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
/* AUX PGA */
SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAIKO_A_RX_AUX_SW_CTL, 7, 0,
@@ -5623,7 +5744,7 @@
snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
/* Set the DMIC sample rate */
- if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6HZ) {
+ if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ) {
switch (pdata->dmic_sample_rate) {
case TAIKO_DMIC_SAMPLE_RATE_2P4MHZ:
dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
@@ -6021,6 +6142,16 @@
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
+void taiko_event_register(
+ int (*machine_event_cb)(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event),
+ struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ taiko->machine_codec_event_cb = machine_event_cb;
+}
+EXPORT_SYMBOL_GPL(taiko_event_register);
+
static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
{
struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
@@ -6046,6 +6177,7 @@
int ret = 0;
struct snd_soc_codec *codec;
struct taiko_priv *taiko;
+ int rco_clk_rate;
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
taiko = snd_soc_codec_get_drvdata(codec);
@@ -6076,8 +6208,16 @@
if (taiko->mbhc_started) {
wcd9xxx_mbhc_deinit(&taiko->mbhc);
taiko->mbhc_started = false;
+
+ if (TAIKO_IS_1_0(wcd9xxx->version))
+ rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
+
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAIKO);
+ taiko_enable_mbhc_micbias,
+ WCD9XXX_MBHC_VERSION_TAIKO,
+ rco_clk_rate);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
} else {
@@ -6087,6 +6227,8 @@
taiko->mbhc_started = true;
}
}
+ taiko->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
+
mutex_unlock(&codec->mutex);
return ret;
}
@@ -6209,7 +6351,7 @@
struct wcd9xxx *wcd9xxx;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
- int i;
+ int i, rco_clk_rate;
void *ptr = NULL;
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -6247,9 +6389,16 @@
taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
+ if (TAIKO_IS_1_0(core->version))
+ rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
+
/* init and start mbhc */
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAIKO);
+ taiko_enable_mbhc_micbias,
+ WCD9XXX_MBHC_VERSION_TAIKO,
+ rco_clk_rate);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
goto err_init;
@@ -6264,11 +6413,13 @@
taiko->aux_pga_cnt = 0;
taiko->aux_l_gain = 0x1F;
taiko->aux_r_gain = 0x1F;
+ taiko->ldo_h_users = 0;
+ taiko->micb_2_users = 0;
taiko_update_reg_defaults(codec);
pr_debug("%s: MCLK Rate = %x\n", __func__, wcd9xxx->mclk_rate);
if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x0);
- else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6HZ)
+ else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ)
snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x2);
taiko_codec_init_reg(codec);
ret = taiko_handle_pdata(taiko);
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index a4dbd7a..8f222ad 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -18,6 +18,7 @@
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include "wcd9xxx-mbhc.h"
#include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
#define TAIKO_NUM_REGISTERS 0x400
#define TAIKO_MAX_REGISTER (TAIKO_NUM_REGISTERS-1)
@@ -148,4 +149,9 @@
extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
enum afe_config_type config_type);
+extern void taiko_event_register(
+ int (*machine_event_cb)(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event),
+ struct snd_soc_codec *codec);
+
#endif
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 6bc581c..316742d 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -73,4 +73,8 @@
extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
struct wcd9xxx_resmgr *resmgr);
+enum wcd9xxx_codec_event {
+ WCD9XXX_CODEC_EVENT_CODEC_UP = 0,
+};
+
#endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index bfd496b..e853061 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/firmware.h>
@@ -47,7 +46,7 @@
SND_JACK_BTN_6 | SND_JACK_BTN_7)
#define NUM_DCE_PLUG_DETECT 3
-#define NUM_DCE_PLUG_INS_DETECT 4
+#define NUM_DCE_PLUG_INS_DETECT 5
#define NUM_ATTEMPTS_INSERT_DETECT 25
#define NUM_ATTEMPTS_TO_REPORT 5
@@ -75,7 +74,6 @@
#define MCLK_RATE_12288KHZ 12288000
#define MCLK_RATE_9600KHZ 9600000
-#define WCD9XXX_RCO_CLK_RATE MCLK_RATE_12288KHZ
#define DEFAULT_DCE_STA_WAIT 55
#define DEFAULT_DCE_WAIT 60000
@@ -83,20 +81,20 @@
#define VDDIO_MICBIAS_MV 1800
+#define WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US 5000
+
#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
-#define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
+#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
#define WCD9XXX_MEAS_DELTA_MAX_MV 50
#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
#define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
#define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
+#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
#define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
-#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAIKO 28
-#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAPAN 21
-
-static bool detect_use_vddio_switch;
+static bool detect_use_vddio_switch = true;
struct wcd9xxx_mbhc_detect {
u16 dce;
@@ -278,6 +276,11 @@
codec = mbhc->codec;
+ if (mbhc->micbias_enable) {
+ pr_debug("%s: micbias is already on\n", __func__);
+ return;
+ }
+
if (vddio_switch && !mbhc->mbhc_micbias_switched &&
(!checkpolling || mbhc->polling_active)) {
if (restartpolling)
@@ -802,6 +805,12 @@
mbhc->buttons_pressed &=
~WCD9XXX_JACK_BUTTON_MASK;
}
+
+ if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
+ pr_debug("%s: Disabling micbias\n", __func__);
+ mbhc->micbias_enable_cb(mbhc->codec, false);
+ mbhc->micbias_enable = false;
+ }
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
@@ -815,8 +824,17 @@
if (mbhc->mbhc_cfg->detect_extn_cable) {
/* Report removal of current jack type */
if (mbhc->hph_status && mbhc->hph_status != jack_type) {
+ if (mbhc->micbias_enable &&
+ mbhc->micbias_enable_cb &&
+ mbhc->hph_status == SND_JACK_HEADSET) {
+ pr_debug("%s: Disabling micbias\n",
+ __func__);
+ mbhc->micbias_enable_cb(mbhc->codec,
+ false);
+ mbhc->micbias_enable = false;
+ }
pr_debug("%s: Reporting removal (%x)\n",
- __func__, mbhc->hph_status);
+ __func__, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
mbhc->hph_status = 0;
@@ -835,6 +853,11 @@
} else if (jack_type == SND_JACK_LINEOUT) {
mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
}
+
+ if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
+ pr_debug("%s: Enabling micbias\n", __func__);
+ mbhc->micbias_enable_cb(mbhc->codec, true);
+ }
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -882,9 +905,9 @@
vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
if (tovddio)
- r = v * vddio_k / mb_k;
+ r = v * (vddio_k + 4) / (mb_k + 4);
else
- r = v * mb_k / vddio_k;
+ r = v * (mb_k + 4) / (vddio_k + 4);
return r;
}
@@ -988,19 +1011,17 @@
return __wcd9xxx_codec_sta_dce(mbhc, dce, false, norel);
}
-static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
- u16 bias_value)
+static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
+ u16 bias_value, s16 z)
{
- s16 value, z, mb;
+ s16 value, mb;
s32 mv;
value = bias_value;
if (dce) {
- z = (mbhc->mbhc_data.dce_z);
mb = (mbhc->mbhc_data.dce_mb);
mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
} else {
- z = (mbhc->mbhc_data.sta_z);
mb = (mbhc->mbhc_data.sta_mb);
mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
}
@@ -1008,6 +1029,14 @@
return mv;
}
+static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
+ u16 bias_value)
+{
+ s16 z;
+ z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
+ return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z);
+}
+
/* called only from interrupt which is under codec_resource_lock acquisition */
static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
@@ -1080,7 +1109,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
- snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+ __wcd9xxx_switch_micbias(mbhc, 0, false, false);
usleep_range(generic->t_shutdown_plug_rem,
generic->t_shutdown_plug_rem);
@@ -1117,6 +1146,7 @@
static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
{
+ pr_debug("%s: vddio %d\n", __func__, on);
if (on) {
snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
1 << 7, 1 << 7);
@@ -1160,7 +1190,7 @@
int ch;
enum wcd9xxx_mbhc_plug_type type;
int vdce;
- struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL;
+ struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL, *dvddio = NULL;
int maxv = 0, minv = 0;
const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
@@ -1182,7 +1212,7 @@
d->_type = PLUG_TYPE_HIGH_HPH;
ch += d->hphl_status & 0x01;
- if (!d->swap_gnd && !d->hwvalue) {
+ if (!d->swap_gnd && !d->hwvalue && !d->vddio) {
if (maxv < d->_vdces)
maxv = d->_vdces;
if (!minv || minv > d->_vdces)
@@ -1215,6 +1245,11 @@
}
for (i = 0, d = dt; i < size; i++, d++) {
+ if (d->vddio) {
+ dvddio = d;
+ continue;
+ }
+
if ((i > 0) && (d->_type != dprev->_type)) {
pr_debug("%s: Invalid, inconsistent types\n", __func__);
type = PLUG_TYPE_INVALID;
@@ -1249,11 +1284,69 @@
__func__, type);
type = PLUG_TYPE_INVALID;
}
+ if (type == PLUG_TYPE_HEADSET && dvddio) {
+ if ((dvddio->_vdces > hs_max) ||
+ (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
+ pr_debug("%s: Headset with threshold on MIC detected\n",
+ __func__);
+ if (mbhc->mbhc_cfg->micbias_enable_flags &
+ (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
+ mbhc->micbias_enable = true;
+ } else {
+ pr_debug("%s: Headset with regular MIC detected\n",
+ __func__);
+ if (mbhc->mbhc_cfg->micbias_enable_flags &
+ (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET))
+ mbhc->micbias_enable = true;
+ }
+ }
exit:
- pr_debug("%s: Plug type %d detected\n", __func__, type);
+ pr_debug("%s: Plug type %d detected, micbias_enable %d\n", __func__,
+ type, mbhc->micbias_enable);
return type;
}
+/*
+ * Pull down MBHC micbias for provided duration in microsecond.
+ */
+static int wcd9xxx_pull_down_micbias(struct wcd9xxx_mbhc *mbhc, int us)
+{
+ bool micbiasconn = false;
+ struct snd_soc_codec *codec = mbhc->codec;
+ const u16 ctlreg = mbhc->mbhc_bias_regs.ctl_reg;
+
+ /*
+ * Disable MBHC to micbias connection to pull down
+ * micbias and pull down micbias for a moment.
+ */
+ if ((snd_soc_read(mbhc->codec, ctlreg) & 0x01)) {
+ WARN_ONCE(1, "MBHC micbias is already pulled down unexpectedly\n");
+ return -EFAULT;
+ }
+
+ if ((snd_soc_read(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL) & 1 << 4)) {
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+ 1 << 4, 0);
+ micbiasconn = true;
+ }
+
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
+
+ /*
+ * Pull down for 1ms to discharge bias. Give small margin (10us) to be
+ * able to get consistent result across DCEs.
+ */
+ usleep_range(1000, 1000 + 10);
+
+ if (micbiasconn)
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+ 1 << 4, 1 << 4);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+ usleep_range(us, us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+
+ return 0;
+}
+
static enum wcd9xxx_mbhc_plug_type
wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
{
@@ -1275,6 +1368,12 @@
plug_type_ptr =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+ /*
+ * cfilter in fast mode requires 1ms to charge up and down micbias
+ * fully.
+ */
+ (void) wcd9xxx_pull_down_micbias(mbhc,
+ WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
rt[0].swap_gnd = false;
@@ -1283,7 +1382,7 @@
for (i = 1; i < NUM_DCE_PLUG_INS_DETECT; i++) {
rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 2);
if (detect_use_vddio_switch)
- rt[i].vddio = (i == NUM_DCE_PLUG_INS_DETECT - 1);
+ rt[i].vddio = (i == 1);
else
rt[i].vddio = false;
rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
@@ -1292,6 +1391,15 @@
wcd9xxx_codec_hphr_gnd_switch(codec, true);
if (rt[i].vddio)
wcd9xxx_onoff_vddio_switch(mbhc, true);
+ /*
+ * Pull down micbias to detect headset with mic which has
+ * threshold and to have more consistent voltage measurements.
+ *
+ * cfilter in fast mode requires 1ms to charge up and down
+ * micbias fully.
+ */
+ (void) wcd9xxx_pull_down_micbias(mbhc,
+ WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
if (rt[i].vddio)
wcd9xxx_onoff_vddio_switch(mbhc, false);
@@ -1490,6 +1598,11 @@
*/
wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
msleep(100);
+
+ /* if PA is already on, switch micbias source to VDDIO */
+ if (mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
+ __wcd9xxx_switch_micbias(mbhc, 1, false, false);
wcd9xxx_start_hs_polling(mbhc);
} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
if (mbhc->mbhc_cfg->detect_extn_cable) {
@@ -1722,12 +1835,12 @@
/* called only from interrupt which is under codec_resource_lock acquisition */
static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
{
- short bias_value;
+ s16 dce;
+ unsigned long timeout;
bool removed = true;
struct snd_soc_codec *codec = mbhc->codec;
const struct wcd9xxx_mbhc_general_cfg *generic =
WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
- int min_us = FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
pr_debug("%s: enter\n", __func__);
if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
@@ -1739,23 +1852,21 @@
}
usleep_range(generic->t_shutdown_plug_rem,
- generic->t_shutdown_plug_rem);
+ generic->t_shutdown_plug_rem);
+ timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS);
do {
- bias_value = wcd9xxx_codec_sta_dce(mbhc, 1, true);
- pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value), min_us);
- if (bias_value <
+ dce = wcd9xxx_codec_sta_dce(mbhc, 1, true);
+ pr_debug("%s: DCE 0x%x,%d\n", __func__, dce,
+ wcd9xxx_codec_sta_dce_v(mbhc, 1, dce));
+ if (dce <
wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
- pr_debug("%s: checking false removal\n", __func__);
- msleep(500);
- removed = !wcd9xxx_hs_remove_settle(mbhc);
- pr_debug("%s: headset %sactually removed\n", __func__,
- removed ? "" : "not ");
+ removed = false;
break;
}
- min_us -= mbhc->mbhc_data.t_dce;
- } while (min_us > 0);
+ } while (!time_after(jiffies, timeout));
+ pr_debug("%s: headset %sactually removed\n", __func__,
+ removed ? "" : "not ");
if (removed) {
if (mbhc->mbhc_cfg->detect_extn_cable) {
@@ -1812,7 +1923,6 @@
static irqreturn_t wcd9xxx_hs_remove_irq(int irq, void *data)
{
- bool vddio;
struct wcd9xxx_mbhc *mbhc = data;
pr_debug("%s: enter, removal interrupt\n", __func__);
@@ -1831,25 +1941,12 @@
WCD9XXX_COND_HPH, false);
}
- vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
- mbhc->mbhc_micbias_switched);
- if (vddio)
- __wcd9xxx_switch_micbias(mbhc, 0, false, true);
-
if (mbhc->mbhc_cfg->detect_extn_cable &&
!wcd9xxx_swch_level_remove(mbhc))
wcd9xxx_hs_remove_irq_noswch(mbhc);
else
wcd9xxx_hs_remove_irq_swch(mbhc);
- /*
- * if driver turned off vddio switch and headset is not removed,
- * turn on the vddio switch back, if headset is removed then vddio
- * switch is off by time now and shouldn't be turn on again from here
- */
- if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
- __wcd9xxx_switch_micbias(mbhc, 1, true, true);
-
if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
WCD9XXX_COND_HPH, true);
@@ -2457,18 +2554,45 @@
return mask;
}
+void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
+{
+ s16 reg0, reg1;
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+ /* Pull down micbias to ground and disconnect vddio switch */
+ reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x81, 0x1);
+ reg1 = snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 1 << 7, 0);
+
+ /* Disconnect override from micbias */
+ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
+ usleep_range(1000, 1000 + 1000);
+ *sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
+ *dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+ /* Connect override from micbias */
+ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 4);
+ /* Disable pull down micbias to ground */
+ snd_soc_write(codec, mbhc->mbhc_bias_regs.mbhc_reg, reg1);
+ snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
+}
+
irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
{
int i, mask;
- short dce, sta;
- s32 mv, mv_s, stamv_s;
bool vddio;
u8 mbhc_status;
+ s16 dce_z, sta_z;
int btn = -1, meas = 0;
struct wcd9xxx_mbhc *mbhc = data;
const struct wcd9xxx_mbhc_btn_detect_cfg *d =
WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
short btnmeas[d->n_btn_meas + 1];
+ short dce[d->n_btn_meas + 1], sta;
+ s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
+ s32 stamv, stamv_s;
struct snd_soc_codec *codec = mbhc->codec;
struct wcd9xxx *core = mbhc->resmgr->core;
int n_btn_meas = d->n_btn_meas;
@@ -2492,9 +2616,6 @@
goto done;
}
- dce = wcd9xxx_read_dce_result(codec);
- mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
-
/* If switch nterrupt already kicked in, ignore button press */
if (mbhc->in_swch_irq_handler) {
pr_debug("%s: Swtich level changed, ignore button press\n",
@@ -2506,13 +2627,10 @@
/* Measure scaled HW DCE */
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
- mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
/* Measure scaled HW STA */
+ dce[0] = wcd9xxx_read_dce_result(codec);
sta = wcd9xxx_read_sta_result(codec);
- stamv_s = wcd9xxx_codec_sta_dce_v(mbhc, 0, sta);
- if (vddio)
- stamv_s = scale_v_micb_vddio(mbhc, stamv_s, false);
if (mbhc_status != STATUS_REL_DETECTION) {
if (mbhc->mbhc_last_resume &&
!time_after(jiffies, mbhc->mbhc_last_resume + HZ)) {
@@ -2522,30 +2640,55 @@
} else {
pr_debug("%s: Button is released without resume",
__func__);
- btn = wcd9xxx_determine_button(mbhc, mv_s);
+ wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+ stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+ if (vddio)
+ stamv_s = scale_v_micb_vddio(mbhc, stamv,
+ false);
+ else
+ stamv_s = stamv;
+ mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
+ dce_z);
+ mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
+ false) : mv[0];
+ btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
if (btn != wcd9xxx_determine_button(mbhc, stamv_s))
btn = -1;
goto done;
}
}
+ for (meas = 1; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1)));
+ meas++)
+ dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+ wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+
+ stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+ if (vddio)
+ stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
+ else
+ stamv_s = stamv;
pr_debug("%s: Meas HW - STA 0x%x,%d,%d\n", __func__,
- sta & 0xFFFF, wcd9xxx_codec_sta_dce_v(mbhc, 0, sta), stamv_s);
+ sta & 0xFFFF, stamv, stamv_s);
/* determine pressed button */
- btnmeas[meas++] = wcd9xxx_determine_button(mbhc, mv_s);
+ mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
+ mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
+ btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
- dce & 0xFFFF, mv, mv_s, btnmeas[meas - 1]);
+ dce[0] & 0xFFFF, mv[0], mv_s[0], btnmeas[0]);
if (n_btn_meas == 0)
btn = btnmeas[0];
- for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
- dce = wcd9xxx_codec_sta_dce(mbhc, 1, false);
- mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
- mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
-
- btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s);
+ for (meas = 1; (n_btn_meas && d->n_btn_meas &&
+ (meas < (d->n_btn_meas + 1))); meas++) {
+ mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z);
+ mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
+ mv[meas];
+ btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
pr_debug("%s: Meas %d - DCE 0x%x,%d,%d button %d\n",
- __func__, meas, dce & 0xFFFF, mv, mv_s, btnmeas[meas]);
+ __func__, meas, dce[meas] & 0xFFFF, mv[meas],
+ mv_s[meas], btnmeas[meas]);
/*
* if large enough measurements are collected,
* start to check if last all n_btn_con measurements were
@@ -2819,9 +2962,11 @@
ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
if (ret)
goto gen_err;
- usleep_range(WCD9XXX_MUX_SWITCH_READY_WAIT_US,
- WCD9XXX_MUX_SWITCH_READY_WAIT_US +
- WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ /*
+ * Hardware that has external cap can delay mic bias ramping down up
+ * to 50ms.
+ */
+ msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
/* DCE measurement for 0 voltage */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
@@ -2841,7 +2986,11 @@
ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
if (ret)
goto gen_err;
- usleep_range(100, 100);
+ /*
+ * Hardware that has external cap can delay mic bias ramping down up
+ * to 50ms.
+ */
+ msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
@@ -2854,7 +3003,11 @@
ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
if (ret)
goto gen_err;
- usleep_range(100, 100);
+ /*
+ * Hardware that has external cap can delay mic bias ramping down up
+ * to 50ms.
+ */
+ msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta);
mbhc->mbhc_data.sta_mb = wcd9xxx_read_sta_result(codec);
@@ -2959,10 +3112,10 @@
switch (mbhc->mbhc_version) {
case WCD9XXX_MBHC_VERSION_TAIKO:
- jack_irq = WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAIKO;
+ jack_irq = WCD9320_IRQ_MBHC_JACK_SWITCH;
break;
case WCD9XXX_MBHC_VERSION_TAPAN:
- jack_irq = WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAPAN;
+ jack_irq = WCD9306_IRQ_MBHC_JACK_SWITCH;
break;
default:
return -EINVAL;
@@ -3092,8 +3245,8 @@
const s16 v_br_h =
wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
- n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
+ n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",
+ p->dce_z, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
@@ -3240,18 +3393,31 @@
enum wcd9xxx_micbias_num ret;
switch (event) {
case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_1_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
ret = MBHC_MICBIAS1;
break;
case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_2_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
ret = MBHC_MICBIAS2;
break;
case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_3_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
ret = MBHC_MICBIAS3;
break;
case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_4_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
ret = MBHC_MICBIAS4;
break;
default:
+ WARN_ONCE(1, "Cannot convert event %d to micbias\n", event);
ret = MBHC_MICBIAS_INVALID;
break;
}
@@ -3349,33 +3515,41 @@
case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
if (mbhc->mbhc_cfg->micbias ==
wcd9xxx_event_to_micbias(event) &&
- wcd9xxx_is_hph_pa_on(codec))
+ (mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
wcd9xxx_switch_micbias(mbhc, 1);
break;
/* PA usage change */
case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
+ set_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
- /* if micbias is enabled, switch to vddio */
+ /* if micbias is not enabled, switch to vddio */
wcd9xxx_switch_micbias(mbhc, 1);
break;
case WCD9XXX_EVENT_PRE_HPHR_PA_ON:
- /* Not used now */
+ set_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
break;
case WCD9XXX_EVENT_POST_HPHL_PA_OFF:
+ clear_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
/* if HPH PAs are off, report OCP and switch back to CFILT */
clear_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
if (mbhc->hph_status & SND_JACK_OC_HPHL)
hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
- wcd9xxx_switch_micbias(mbhc, 0);
+ if (!(mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+ wcd9xxx_switch_micbias(mbhc, 0);
break;
case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
+ clear_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
/* if HPH PAs are off, report OCP and switch back to CFILT */
clear_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
if (mbhc->hph_status & SND_JACK_OC_HPHR)
hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
- wcd9xxx_switch_micbias(mbhc, 0);
+ if (!(mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+ wcd9xxx_switch_micbias(mbhc, 0);
break;
/* Clock usage change */
case WCD9XXX_EVENT_PRE_MCLK_ON:
@@ -3406,7 +3580,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
0 << 4);
/* Re-calibrate clock rate dependent values */
- wcd9xxx_update_mbhc_clk_rate(mbhc, WCD9XXX_RCO_CLK_RATE);
+ wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->rco_clk_rate);
/* If clock source changes, stop and restart polling */
if (wcd9xxx_mbhc_polling(mbhc)) {
wcd9xxx_calibrate_hs_polling(mbhc);
@@ -3472,7 +3646,10 @@
* NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
*/
int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
- struct snd_soc_codec *codec, int version)
+ struct snd_soc_codec *codec,
+ int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
+ int version,
+ int rco_clk_rate)
{
int ret;
void *core;
@@ -3495,7 +3672,9 @@
mbhc->codec = codec;
mbhc->resmgr = resmgr;
mbhc->resmgr->mbhc = mbhc;
+ mbhc->micbias_enable_cb = micbias_enable_cb;
mbhc->mbhc_version = version;
+ mbhc->rco_clk_rate = rco_clk_rate;
if (mbhc->headset_jack.jack == NULL) {
ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
@@ -3618,7 +3797,18 @@
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_JACK_SWITCH, mbhc);
+ switch (mbhc->mbhc_version) {
+ case WCD9XXX_MBHC_VERSION_TAIKO:
+ wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH, mbhc);
+ break;
+ case WCD9XXX_MBHC_VERSION_TAPAN:
+ wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+ break;
+ default:
+ pr_err("%s: irq free failed! Invalid MBHC version %d\n",
+ __func__, mbhc->mbhc_version);
+ }
+
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 4f8f3cf..71a62b2 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -34,6 +34,12 @@
MBHC_V_IDX_NUM,
};
+enum mbhc_cal_type {
+ MBHC_CAL_MCLK,
+ MBHC_CAL_RCO,
+ MBHC_CAL_NUM,
+};
+
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
@@ -78,6 +84,11 @@
MBHC_MICBIAS4,
};
+enum wcd9xx_mbhc_micbias_enable_bits {
+ MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
+ MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
+};
+
enum wcd9xxx_mbhc_state {
MBHC_STATE_NONE = -1,
MBHC_STATE_POTENTIAL,
@@ -99,6 +110,11 @@
TAIKO_NUM_CLK_FREQS,
};
+enum wcd9xxx_mbhc_event_state {
+ MBHC_EVENT_PA_HPHL,
+ MBHC_EVENT_PA_HPHR,
+};
+
struct wcd9xxx_mbhc_general_cfg {
u8 t_ldoh;
u8 t_bg_fast_settle;
@@ -196,6 +212,8 @@
int gpio_level_insert;
bool insert_detect; /* codec has own MBHC_INSERT_DETECT */
bool detect_extn_cable;
+ /* bit mask of enum wcd9xx_mbhc_micbias_enable_bits */
+ unsigned long micbias_enable_flags;
/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
bool (*swap_gnd_mic) (struct snd_soc_codec *);
};
@@ -241,8 +259,13 @@
bool no_mic_headset_override;
- /* track PA/DAC state */
+ /* track PA/DAC state to sync with userspace */
unsigned long hph_pa_dac_state;
+ /*
+ * save codec's state with resmgr event notification
+ * bit flags of enum wcd9xxx_mbhc_event_state
+ */
+ unsigned long event_state;
unsigned long mbhc_last_resume; /* in jiffies */
@@ -253,8 +276,13 @@
struct notifier_block nblock;
+ bool micbias_enable;
+ int (*micbias_enable_cb) (struct snd_soc_codec*, bool);
+
enum wcd9xxx_mbhc_version mbhc_version;
+ u32 rco_clk_rate;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_poke;
struct dentry *debugfs_mbhc;
@@ -319,7 +347,10 @@
int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
struct wcd9xxx_mbhc_config *mbhc_cfg);
int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
- struct snd_soc_codec *codec, int version);
+ struct snd_soc_codec *codec,
+ int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
+ int version,
+ int rco_clk_rate);
void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
void *wcd9xxx_mbhc_cal_btn_det_mp(
const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 60a76a2..77dbd36 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -659,7 +659,6 @@
bool set;
pr_debug("%s: enter\n", __func__);
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
set = !!test_bit(cond, &resmgr->cond_flags);
list_for_each(l, &resmgr->update_bit_cond_h) {
e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
@@ -675,13 +674,14 @@
void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
enum wcd9xxx_resmgr_cond cond, bool set)
{
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ mutex_lock(&resmgr->update_bit_cond_lock);
if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
(!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
pr_debug("%s: Resource %d condition changed to %s\n", __func__,
cond, set ? "set" : "clear");
wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
}
+ mutex_unlock(&resmgr->update_bit_cond_lock);
}
int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
@@ -700,11 +700,11 @@
entry->shift = shift;
entry->invert = invert;
- WCD9XXX_BCL_LOCK(resmgr);
+ mutex_lock(&resmgr->update_bit_cond_lock);
list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
- WCD9XXX_BCL_UNLOCK(resmgr);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
return 0;
}
@@ -722,7 +722,7 @@
struct wcd9xxx_resmgr_cond_entry *e = NULL;
pr_debug("%s: enter\n", __func__);
- WCD9XXX_BCL_LOCK(resmgr);
+ mutex_lock(&resmgr->update_bit_cond_lock);
list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
if (e->reg == reg && e->shift == shift && e->invert == invert) {
@@ -730,12 +730,12 @@
1 << e->shift,
e->invert << e->shift);
list_del(&e->list);
- WCD9XXX_BCL_UNLOCK(resmgr);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
kfree(e);
return 0;
}
}
- WCD9XXX_BCL_UNLOCK(resmgr);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
__func__, e ? e->reg : 0, e ? e->shift : 0);
@@ -776,12 +776,14 @@
BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
mutex_init(&resmgr->codec_resource_lock);
+ mutex_init(&resmgr->update_bit_cond_lock);
return 0;
}
void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr)
{
+ mutex_destroy(&resmgr->update_bit_cond_lock);
mutex_destroy(&resmgr->codec_resource_lock);
}
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 8acc816..b5f950c 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -127,6 +127,7 @@
unsigned long cond_flags;
struct list_head update_bit_cond_h;
+ struct mutex update_bit_cond_lock;
/*
* Currently, only used for mbhc purpose, to protect
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 7fd62f1..40661ff 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -190,6 +190,23 @@
the machine drivers and the corresponding
DAI-links.
+config SND_SOC_APQ8074
+ tristate "SoC Machine driver for APQ8O74 boards"
+ depends on ARCH_MSM8974
+ select SND_SOC_QDSP6V2
+ 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
+ help
+ To add support for SoC audio on APQ8074.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine drivers and the corresponding
+ DAI-links.
+
config SND_SOC_MSM8226
tristate "SoC Machine driver for MSM8226 boards"
depends on ARCH_MSM8226
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 7ab4811..e206812 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -84,6 +84,10 @@
snd-soc-qdsp6v2-objs := msm-dai-fe.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+# for APQ 8074 sound card driver
+snd-soc-apq8074-objs := apq8074.o
+obj-$(CONFIG_SND_SOC_APQ8074) += snd-soc-apq8074.o
+
#for MDM9625 sound card driver
snd-soc-mdm9625-objs := mdm9625.o
obj-$(CONFIG_SND_SOC_MDM9625) += snd-soc-mdm9625.o
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
new file mode 100644
index 0000000..9a2f83b
--- /dev/null
+++ b/sound/soc/msm/apq8074.c
@@ -0,0 +1,2486 @@
+/* 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
+ * 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/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9320.h"
+#include <linux/io.h>
+
+#define DRV_NAME "apq8074-asoc-taiko"
+
+#define APQ8074_SPK_ON 1
+#define APQ8074_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS 2
+#define MSM_SLIM_0_TX_MAX_CHANNELS 4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
+static int apq8074_auxpcm_rate = 8000;
+#define LO_1_SPK_AMP 0x1
+#define LO_3_SPK_AMP 0x2
+#define LO_2_SPK_AMP 0x4
+#define LO_4_SPK_AMP 0x8
+
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define TAIKO_EXT_CLK_RATE 9600000
+
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
+/* It takes about 13ms for Class-AB PAs to ramp-up */
+#define EXT_CLASS_AB_EN_DELAY 10000
+#define EXT_CLASS_AB_DIS_DELAY 1000
+#define EXT_CLASS_AB_DELAY_DELTA 1000
+
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static inline int param_is_mask(int p)
+{
+ return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK));
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum apq8074_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
+static void *def_taiko_mbhc_cal(void);
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm);
+
+static struct wcd9xxx_mbhc_config mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .micbias = MBHC_MICBIAS2,
+ .mclk_cb_fn = msm_snd_enable_codec_ext_clk,
+ .mclk_rate = TAIKO_EXT_CLK_RATE,
+ .gpio = 0,
+ .gpio_irq = 0,
+ .gpio_level_insert = 1,
+ .detect_extn_cable = true,
+ .insert_detect = true,
+ .swap_gnd_mic = NULL,
+};
+
+struct msm_auxpcm_gpio {
+ unsigned gpio_no;
+ const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+ struct msm_auxpcm_gpio *pin_data;
+ u32 cnt;
+};
+
+struct apq8074_asoc_mach_data {
+ int mclk_gpio;
+ u32 mclk_freq;
+ int us_euro_gpio;
+ struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
+};
+
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX 1
+
+static char *msm_prim_auxpcm_gpio_name[][2] = {
+ {"PRIM_AUXPCM_CLK", "qcom,prim-auxpcm-gpio-clk"},
+ {"PRIM_AUXPCM_SYNC", "qcom,prim-auxpcm-gpio-sync"},
+ {"PRIM_AUXPCM_DIN", "qcom,prim-auxpcm-gpio-din"},
+ {"PRIM_AUXPCM_DOUT", "qcom,prim-auxpcm-gpio-dout"},
+};
+
+static void *lpaif_pri_muxsel_virt_addr;
+
+struct apq8074_liquid_dock_dev {
+ int dock_plug_gpio;
+ int dock_plug_irq;
+ struct snd_soc_dapm_context *dapm;
+ struct work_struct irq_work;
+};
+
+static struct apq8074_liquid_dock_dev *apq8074_liquid_dock_dev;
+static int dock_plug_det = -1;
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+ SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+ SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+ SLIM_2_RX_1 = 147, /* HDMI RX */
+ SLIM_3_RX_1 = 148, /* In-call recording RX */
+ SLIM_3_RX_2 = 149, /* In-call recording RX */
+ SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int ext_ult_spk_amp_gpio = -1;
+static int apq8074_spk_control = 1;
+static int apq8074_ext_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+static int msm_hdmi_rx_ch = 2;
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int msm_proxy_rx_ch = 2;
+
+static struct mutex cdc_mclk_mutex;
+static struct clk *codec_clk;
+static int clk_users;
+static atomic_t prim_auxpcm_rsc_ref;
+
+static int apq8074_liquid_ext_spk_power_amp_init(void)
+{
+ int ret = 0;
+
+ ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-spk-amp-gpio", 0);
+ if (ext_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_spk_amp_gpio, 0);
+
+ if (ext_spk_amp_regulator == NULL) {
+ ext_spk_amp_regulator = regulator_get(&spdev->dev,
+ "qcom,ext-spk-amp");
+
+ if (IS_ERR(ext_spk_amp_regulator)) {
+ pr_err("%s: Cannot get regulator %s.\n",
+ __func__, "qcom,ext-spk-amp");
+
+ gpio_free(ext_spk_amp_gpio);
+ return PTR_ERR(ext_spk_amp_regulator);
+ }
+ }
+ }
+
+ ext_ult_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-ult-spk-amp-gpio", 0);
+
+ if (ext_ult_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_ult_spk_amp_gpio,
+ "ext_ult_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext-ult_spk-amp-gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ }
+
+ return 0;
+}
+
+static void apq8074_liquid_ext_ult_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_ult_spk_amp_gpio, 1);
+ /* time takes enable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_EN_DELAY,
+ EXT_CLASS_AB_EN_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ regulator_disable(ext_spk_amp_regulator);
+ /* time takes disable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_DIS_DELAY,
+ EXT_CLASS_AB_DIS_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external ultrasound SPKR_DRV PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_ext_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ /*time takes enable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_EN_DELAY,
+ EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ regulator_disable(ext_spk_amp_regulator);
+ /*time takes disable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_DIS_DELAY,
+ EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_docking_irq_work(struct work_struct *work)
+{
+ struct apq8074_liquid_dock_dev *dock_dev =
+ container_of(work,
+ struct apq8074_liquid_dock_dev,
+ irq_work);
+
+ struct snd_soc_dapm_context *dapm = dock_dev->dapm;
+
+
+ mutex_lock(&dapm->codec->mutex);
+ dock_plug_det =
+ gpio_get_value(dock_dev->dock_plug_gpio);
+
+
+ if (0 == dock_plug_det) {
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ apq8074_liquid_ext_spk_power_amp_enable(1);
+ } else {
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ apq8074_liquid_ext_spk_power_amp_enable(0);
+ }
+
+ mutex_unlock(&dapm->codec->mutex);
+
+}
+
+static irqreturn_t apq8074_liquid_docking_irq_handler(int irq, void *dev)
+{
+ struct apq8074_liquid_dock_dev *dock_dev = dev;
+
+ /* switch speakers should not run in interrupt context */
+ schedule_work(&dock_dev->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int apq8074_liquid_init_docking(struct snd_soc_dapm_context *dapm)
+{
+ int ret = 0;
+ int dock_plug_gpio = 0;
+
+ /* plug in docking speaker+plug in device OR unplug one of them */
+ u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+ dock_plug_det = 0;
+ dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,dock-plug-det-irq", 0);
+
+ if (dock_plug_gpio >= 0) {
+
+ apq8074_liquid_dock_dev =
+ kzalloc(sizeof(*apq8074_liquid_dock_dev), GFP_KERNEL);
+
+ if (!apq8074_liquid_dock_dev) {
+ pr_err("apq8074_liquid_dock_dev alloc fail.\n");
+ return -ENOMEM;
+ }
+
+ apq8074_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
+
+ ret = gpio_request(apq8074_liquid_dock_dev->dock_plug_gpio,
+ "dock-plug-det-irq");
+ if (ret) {
+ pr_err("%s:failed request apq8074_liquid_dock_plug_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dock_plug_det =
+ gpio_get_value(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ apq8074_liquid_dock_dev->dock_plug_irq =
+ gpio_to_irq(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ apq8074_liquid_dock_dev->dapm = dapm;
+
+ ret = request_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+ apq8074_liquid_docking_irq_handler,
+ dock_plug_irq_flags,
+ "liquid_dock_plug_irq",
+ apq8074_liquid_dock_dev);
+
+ INIT_WORK(
+ &apq8074_liquid_dock_dev->irq_work,
+ apq8074_liquid_docking_irq_work);
+ }
+
+ return 0;
+}
+
+static int apq8074_liquid_ext_spk_power_amp_on(u32 spk)
+{
+ int rc;
+
+ if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP | LO_2_SPK_AMP | LO_4_SPK_AMP)) {
+ pr_debug("%s: External speakers are already on. spk = 0x%x\n",
+ __func__, spk);
+
+ apq8074_ext_spk_pamp |= spk;
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ if (ext_spk_amp_gpio >= 0 &&
+ dock_plug_det == 0)
+ apq8074_liquid_ext_spk_power_amp_enable(1);
+ rc = 0;
+ } else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+ __func__, spk);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+
+static void apq8074_ext_spk_power_amp_on(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ apq8074_liquid_ext_spk_power_amp_on(spk);
+}
+
+static void apq8074_liquid_ext_spk_power_amp_off(u32 spk)
+{
+
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
+
+ pr_debug("%s Left and right speakers case spk = 0x%08x",
+ __func__, spk);
+
+ if (!apq8074_ext_spk_pamp) {
+ if (ext_spk_amp_gpio >= 0 &&
+ dock_plug_det == 0)
+ apq8074_liquid_ext_spk_power_amp_enable(0);
+ apq8074_ext_spk_pamp = 0;
+ }
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void apq8074_ext_spk_power_amp_off(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ apq8074_liquid_ext_spk_power_amp_off(spk);
+}
+
+static void apq8074_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ mutex_lock(&dapm->codec->mutex);
+
+ pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+ if (apq8074_spk_control == APQ8074_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
+ }
+
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
+}
+
+static int apq8074_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+ ucontrol->value.integer.value[0] = apq8074_spk_control;
+ return 0;
+}
+
+static int apq8074_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (apq8074_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ apq8074_spk_control = ucontrol->value.integer.value[0];
+ apq8074_ext_control(codec);
+ return 1;
+}
+
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s()\n", __func__);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_4_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_4_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+
+}
+
+static int msm_ext_spkramp_ultrasound_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+
+ pr_debug("%s()\n", __func__);
+
+ if (!strncmp(w->name, "SPK_ultrasound amp", 19)) {
+ if (!gpio_is_valid(ext_ult_spk_amp_gpio)) {
+ pr_err("%s: ext_ult_spk_amp_gpio isn't configured\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ apq8074_liquid_ext_ult_spk_power_amp_enable(1);
+ else
+ apq8074_liquid_ext_ult_spk_power_amp_enable(0);
+
+ } else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm)
+{
+ int ret = 0;
+ pr_debug("%s: enable = %d clk_users = %d\n",
+ __func__, enable, clk_users);
+
+ mutex_lock(&cdc_mclk_mutex);
+ if (enable) {
+ if (!codec_clk) {
+ dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ clk_users++;
+ if (clk_users != 1)
+ goto exit;
+
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TAIKO_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ taiko_mclk_enable(codec, 1, dapm);
+ } else {
+ pr_err("%s: Error setting Taiko MCLK\n", __func__);
+ clk_users--;
+ goto exit;
+ }
+ } else {
+ if (clk_users > 0) {
+ clk_users--;
+ if (clk_users == 0) {
+ taiko_mclk_enable(codec, 0, dapm);
+ clk_disable_unprepare(codec_clk);
+ }
+ } else {
+ pr_err("%s: Error releasing Taiko MCLK\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+exit:
+ mutex_unlock(&cdc_mclk_mutex);
+ return ret;
+}
+
+static int apq8074_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_clk(w->codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_clk(w->codec, 0, true);
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8074_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ apq8074_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
+
+ SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("SPK_ultrasound amp",
+ msm_ext_spkramp_ultrasound_event),
+
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static const char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
+static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+
+static const char *const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim0_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim0_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+ msm_slim_0_tx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch);
+ return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_btsco_rate = %d", __func__, msm_btsco_rate);
+ ucontrol->value.integer.value[0] = msm_btsco_rate;
+ return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ case 1:
+ msm_btsco_rate = BTSCO_RATE_16KHZ;
+ break;
+ default:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate);
+ return 0;
+}
+
+static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+ msm_hdmi_rx_ch);
+ ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+ if (msm_hdmi_rx_ch > 8) {
+ pr_err("%s: channels exceeded 8.Limiting to max channels-8\n",
+ __func__);
+ msm_hdmi_rx_ch = 8;
+ }
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_btsco_rate;
+ channels->min = channels->max = msm_btsco_ch;
+
+ return 0;
+}
+
+static int apq8074_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = apq8074_auxpcm_rate;
+ return 0;
+}
+
+static int apq8074_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ apq8074_auxpcm_rate = 8000;
+ break;
+ case 1:
+ apq8074_auxpcm_rate = 16000;
+ break;
+ default:
+ apq8074_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+ msm_proxy_rx_ch);
+ ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
+ return 0;
+}
+
+static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+ msm_proxy_rx_ch);
+ return 1;
+}
+
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = apq8074_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+
+static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ channels->min = channels->max = msm_proxy_rx_ch;
+ rate->min = rate->max = 48000;
+ return 0;
+}
+
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ rate->min = rate->max = 48000;
+ return 0;
+}
+
+static int apq8074_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+ channels->min, channels->max);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_bit_format);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_hdmi_rx_ch;
+
+ return 0;
+}
+
+static int msm_aux_pcm_get_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int ret = 0;
+ int i;
+ int j;
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ ret = gpio_request(pin_data->gpio_no,
+ pin_data->gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s\n"
+ "ret = %d\n", __func__,
+ pin_data->gpio_no,
+ pin_data->gpio_name,
+ ret);
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, pin_data->gpio_no);
+ /* Release all GPIOs on failure */
+ for (j = i; j >= 0; j--)
+ gpio_free(pin_data->gpio_no);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int msm_aux_pcm_free_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int i;
+ int ret = 0;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ gpio_free(pin_data->gpio_no);
+ pr_debug("%s: gpio = %d, gpio_name = %s\n",
+ __func__, pin_data->gpio_no,
+ pin_data->gpio_name);
+ }
+err:
+ return ret;
+}
+
+static int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
+ }
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+err:
+ return ret;
+}
+
+static void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+
+ pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (atomic_dec_return(&prim_auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios(auxpcm_ctrl);
+}
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+ .startup = msm_prim_auxpcm_startup,
+ .shutdown = msm_prim_auxpcm_shutdown,
+};
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim0_rx_bit_format);
+ rate->min = rate->max = slim0_rx_sample_rate;
+ channels->min = channels->max = msm_slim_0_rx_ch;
+
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ msm_slim_0_rx_ch);
+
+ return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_slim_0_tx_ch;
+
+ return 0;
+}
+
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ int rc;
+ void *config;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s enter\n", __func__);
+ rate->min = rate->max = 16000;
+ channels->min = channels->max = 1;
+
+ config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+ SLIMBUS_5_TX);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
+static const struct soc_enum msm_snd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(5, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], apq8074_get_spk,
+ apq8074_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", apq8074_auxpcm_enum[0],
+ apq8074_auxpcm_rate_get, apq8074_auxpcm_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+ msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+ slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+ hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
+ SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
+ msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+};
+
+static bool apq8074_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ return true;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Taiko SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TAIKO_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TAIKO_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+
+ pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ err = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (err < 0)
+ return err;
+
+ err = apq8074_liquid_ext_spk_power_amp_init();
+ if (err) {
+ pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ err = apq8074_liquid_init_docking(dapm);
+ if (err) {
+ pr_err("%s: LiQUID 8974 init Docking stat IRQ failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ snd_soc_dapm_new_controls(dapm, apq8074_dapm_widgets,
+ ARRAY_SIZE(apq8074_dapm_widgets));
+
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+
+ snd_soc_dapm_sync(dapm);
+
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ err);
+ goto out;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_AANC_VERSION);
+ err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, err);
+ goto out;
+ }
+ config_data = taiko_get_afe_config(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ /* start mbhc */
+ mbhc_cfg.calibration = def_taiko_mbhc_cal();
+ if (mbhc_cfg.calibration) {
+ err = taiko_hs_detect(codec, &mbhc_cfg);
+ if (err)
+ goto out;
+ else
+ return err;
+ } else {
+ err = -ENOMEM;
+ goto out;
+ }
+out:
+ clk_put(codec_clk);
+ return err;
+}
+
+static int apq8074_snd_startup(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ return 0;
+}
+
+static void *def_taiko_mbhc_cal(void)
+{
+ void *taiko_cal;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_ready, *n_cic, *gain;
+
+ taiko_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(WCD9XXX_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!taiko_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(taiko_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 4);
+ S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(taiko_cal)->X) = (Y))
+ S(mic_current, TAIKO_PID_MIC_5_UA);
+ S(hph_current, TAIKO_PID_MIC_5_UA);
+ S(t_mic_pid, 100);
+ S(t_ins_complete, 250);
+ S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(taiko_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 2400);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal)->X) = (Y))
+ S(c[0], 62);
+ S(c[1], 124);
+ S(nc, 1);
+ S(n_meas, 3);
+ S(mbhc_nsc, 11);
+ S(n_btn_meas, 1);
+ S(n_btn_con, 2);
+ S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal);
+ btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
+ btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
+ MBHC_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = -50;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 61;
+ btn_low[2] = 62;
+ btn_high[2] = 104;
+ btn_low[3] = 105;
+ btn_high[3] = 148;
+ btn_low[4] = 149;
+ btn_high[4] = 189;
+ btn_low[5] = 190;
+ btn_high[5] = 228;
+ btn_low[6] = 229;
+ btn_high[6] = 269;
+ btn_low[7] = 270;
+ btn_high[7] = 500;
+ n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
+ n_ready[0] = 80;
+ n_ready[1] = 68;
+ n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
+ n_cic[0] = 60;
+ n_cic[1] = 47;
+ gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return taiko_cal;
+}
+
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int user_set_tx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ } else {
+
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ /* For tabla_tx1 case */
+ if (codec_dai->id == 1)
+ user_set_tx_ch = msm_slim_0_tx_ch;
+ /* For tabla_tx2 case */
+ else if (codec_dai->id == 3)
+ user_set_tx_ch = params_channels(params);
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d)user_set_tx_ch(%d)tx_ch_cnt(%d)\n",
+ __func__, msm_slim_0_tx_ch, user_set_tx_ch, tx_ch_cnt);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static void apq8074_snd_shudown(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+}
+
+static struct snd_soc_ops apq8074_be_ops = {
+ .startup = apq8074_snd_startup,
+ .hw_params = msm_snd_hw_params,
+ .shutdown = apq8074_snd_shudown,
+};
+
+
+
+static int apq8074_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ num_rx_ch = params_channels(params);
+
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ } else {
+
+ num_tx_ch = params_channels(params);
+
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+
+static struct snd_soc_ops apq8074_slimbus_2_be_ops = {
+ .startup = apq8074_snd_startup,
+ .hw_params = apq8074_slimbus_2_hw_params,
+ .shutdown = apq8074_snd_shudown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link apq8074_common_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSM8974 Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = "MSM8974 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .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,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = "MSM8974 LPA",
+ .stream_name = "LPA",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-lpa",
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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",
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM8974 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .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_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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",
+ },
+ {
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .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",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
+ {
+ .name = "MSM8974 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {
+ .name = "Listen Audio Service",
+ .stream_name = "Listen Audio Service",
+ .cpu_dai_name = "LSM",
+ .platform_name = "msm-lsm-client",
+ .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,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ /* Backend BT/FM DAI Links */
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12288",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12289",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.4106",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.4107",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_mad1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &apq8074_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &apq8074_slimbus_2_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link apq8074_hdmi_dai_link[] = {
+/* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-hdmi-audio-codec-rx",
+ .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = apq8074_hdmi_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link apq8074_dai_links[
+ ARRAY_SIZE(apq8074_common_dai_links) +
+ ARRAY_SIZE(apq8074_hdmi_dai_link)];
+
+struct snd_soc_card snd_soc_card_apq8074 = {
+ .name = "apq8074-taiko-snd-card",
+};
+
+static int apq8074_dtparse_auxpcm(struct platform_device *pdev,
+ struct msm_auxpcm_ctrl **auxpcm_ctrl,
+ char *msm_auxpcm_gpio_name[][2])
+{
+ int ret = 0;
+ int i = 0;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ struct msm_auxpcm_ctrl *ctrl;
+ unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ int auxpcm_cnt = 0;
+
+ pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+ sizeof(struct msm_auxpcm_gpio)),
+ GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+ gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+ msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+ 0, &flags);
+
+ if (gpio_no[i] > 0) {
+ pin_data[i].gpio_name =
+ msm_auxpcm_gpio_name[auxpcm_cnt][GPIO_NAME_INDEX];
+ pin_data[i].gpio_no = gpio_no[i];
+ dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+ "0x%x\n", __func__,
+ pin_data[i].gpio_name,
+ pin_data[i].gpio_no);
+ auxpcm_cnt++;
+ } else {
+ dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+ __func__,
+ msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+ gpio_no[i]);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ctrl->pin_data = pin_data;
+ ctrl->cnt = auxpcm_cnt;
+ *auxpcm_ctrl = ctrl;
+ return ret;
+
+err:
+ if (pin_data)
+ devm_kfree(&pdev->dev, pin_data);
+ return ret;
+}
+
+static int apq8074_prepare_codec_mclk(struct snd_soc_card *card)
+{
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->mclk_gpio) {
+ ret = gpio_request(pdata->mclk_gpio, "TAIKO_CODEC_PMIC_MCLK");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko mclk gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int apq8074_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->us_euro_gpio) {
+ dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static __devinit int apq8074_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_card_apq8074;
+ struct apq8074_asoc_mach_data *pdata;
+ int ret;
+ const char *auxpcm_pri_gpio_set = NULL;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "No platform supplied from device tree\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct apq8074_asoc_mach_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Can't allocate apq8074_asoc_mach_data\n");
+ return -ENOMEM;
+ }
+
+ /* Parse AUXPCM info from DT */
+ ret = apq8074_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
+ msm_prim_auxpcm_gpio_name);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Auxpcm pin data parse failed\n", __func__);
+ goto err;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card,
+ "qcom,audio-routing");
+ if (ret)
+ goto err;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,taiko-mclk-clk-freq", &pdata->mclk_freq);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,taiko-mclk-clk-freq",
+ pdev->dev.of_node->full_name);
+ goto err;
+ }
+
+ if (pdata->mclk_freq != 9600000) {
+ dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
+ pdata->mclk_freq);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-mclk-gpios", 0);
+ if (pdata->mclk_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+ pdata->mclk_gpio);
+ ret = -ENODEV;
+ goto err;
+ }
+
+
+ ret = apq8074_prepare_codec_mclk(card);
+ if (ret)
+ goto err;
+
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
+ dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
+ __func__);
+
+ memcpy(apq8074_dai_links, apq8074_common_dai_links,
+ sizeof(apq8074_common_dai_links));
+
+ memcpy(apq8074_dai_links + ARRAY_SIZE(apq8074_common_dai_links),
+ apq8074_hdmi_dai_link, sizeof(apq8074_hdmi_dai_link));
+
+ card->dai_link = apq8074_dai_links;
+ card->num_links = ARRAY_SIZE(apq8074_dai_links);
+ } else {
+ dev_info(&pdev->dev, "%s(): No hdmi audio support\n", __func__);
+
+ card->dai_link = apq8074_common_dai_links;
+ card->num_links = ARRAY_SIZE(apq8074_common_dai_links);
+ }
+
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,us-euro-gpios",
+ pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected %d",
+ "qcom,us-euro-gpios", pdata->us_euro_gpio);
+ mbhc_cfg.swap_gnd_mic = apq8074_swap_gnd_mic;
+ }
+
+ ret = apq8074_prepare_us_euro(card);
+ if (ret)
+ dev_err(&pdev->dev, "apq8074_prepare_us_euro failed (%d)\n",
+ ret);
+
+ mutex_init(&cdc_mclk_mutex);
+ atomic_set(&prim_auxpcm_rsc_ref, 0);
+ spdev = pdev;
+ ext_spk_amp_regulator = NULL;
+ apq8074_liquid_dock_dev = NULL;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,prim-auxpcm-gpio-set",
+ pdev->dev.of_node->full_name);
+ goto err;
+ }
+ if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
+ lpaif_pri_muxsel_virt_addr =
+ ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ } else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
+ lpaif_pri_muxsel_virt_addr =
+ ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+ } else {
+ dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
+ auxpcm_pri_gpio_set);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ return 0;
+
+err:
+ if (pdata->mclk_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ gpio_free(pdata->mclk_gpio);
+ pdata->mclk_gpio = 0;
+ }
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int __devexit apq8074_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ if (ext_spk_amp_regulator)
+ regulator_put(ext_spk_amp_regulator);
+
+ if (gpio_is_valid(ext_ult_spk_amp_gpio))
+ gpio_free(ext_ult_spk_amp_gpio);
+
+ gpio_free(pdata->mclk_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ gpio_free(ext_spk_amp_gpio);
+
+ if (apq8074_liquid_dock_dev != NULL) {
+ if (apq8074_liquid_dock_dev->dock_plug_gpio)
+ gpio_free(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ if (apq8074_liquid_dock_dev->dock_plug_irq)
+ free_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+ apq8074_liquid_dock_dev);
+
+ kfree(apq8074_liquid_dock_dev);
+ apq8074_liquid_dock_dev = NULL;
+ }
+
+ iounmap(lpaif_pri_muxsel_virt_addr);
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static const struct of_device_id apq8074_asoc_machine_of_match[] = {
+ { .compatible = "qcom,apq8074-audio-taiko", },
+ {},
+};
+
+static struct platform_driver apq8074_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = apq8074_asoc_machine_of_match,
+ },
+ .probe = apq8074_asoc_machine_probe,
+ .remove = __devexit_p(apq8074_asoc_machine_remove),
+};
+module_platform_driver(apq8074_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, apq8074_asoc_machine_of_match);
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index f3ccb33..fd21c38 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -309,18 +309,18 @@
pr_err("set format for codec dai failed\n");
return ret;
}
- }
- /* This sets the CONFIG PARAMETER WS_SRC.
- * 1 means internal clock master mode.
- * 0 means external clock slave mode.
- */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- pr_err("set fmt cpu dai failed\n");
+ /* This sets the CONFIG PARAMETER WS_SRC.
+ * 1 means internal clock master mode.
+ * 0 means external clock slave mode.
+ */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- pr_err("set fmt for codec dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt for codec dai failed\n");
+ }
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
index 84ea9c6..ecf8394 100644
--- a/sound/soc/msm/msm-pcm-loopback.c
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -22,11 +22,17 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include "msm-pcm-routing.h"
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+ LOOPBACK_VOL_MAX_STEPS);
+
struct msm_pcm_loopback {
struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream;
@@ -42,6 +48,7 @@
int capture_start;
int session_id;
struct audio_client *audio_client;
+ int volume;
};
static void stop_pcm(struct msm_pcm_loopback *pcm);
@@ -99,6 +106,24 @@
}
}
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+ int rc = 0;
+
+ pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+ if (prtd) {
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
static int msm_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -111,6 +136,7 @@
mutex_lock(&pcm->lock);
snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+ pcm->volume = 0x2000;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
pcm->playback_substream = substream;
@@ -155,6 +181,13 @@
pcm->audio_client->perf_mode,
pcm->session_id, pcm->playback_substream->stream,
event);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pcm->playback_substream = substream;
+ ret = pcm_loopback_set_volume(pcm, pcm->volume);
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "Error %d setting volume", ret);
+ }
}
dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
__func__ , pcm->instance, substream->pcm->id);
@@ -290,6 +323,38 @@
.trigger = msm_pcm_trigger,
};
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = kcontrol->private_data;
+ struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+ struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+ int volume = ucontrol->value.integer.value[0];
+
+ rc = pcm_loopback_set_volume(prtd, volume);
+ return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1,
+ rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->tlv.p = loopback_rx_vol_gain;
+ return 0;
+}
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
@@ -298,6 +363,10 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret)
+ dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index c37e932..a05a216 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.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
@@ -165,7 +165,7 @@
/* assume data size = 0 during flushing */
if (in_frame_info[token][0]) {
- prtd->pcm_irq_pos += in_frame_info[token][0];
+ prtd->pcm_irq_pos += prtd->pcm_count;
pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
if (atomic_read(&prtd->start))
snd_pcm_period_elapsed(substream);
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 86e3d75..22cd61a 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -72,6 +72,7 @@
.gpio_irq = 0,
.gpio_level_insert = 0,
.detect_extn_cable = true,
+ .micbias_enable_flags = 0,
.insert_detect = true,
.swap_gnd_mic = NULL,
};
@@ -90,6 +91,7 @@
int mclk_gpio;
u32 mclk_freq;
struct msm_auxpcm_ctrl *auxpcm_ctrl;
+ u32 us_euro_gpio;
};
#define GPIO_NAME_INDEX 0
@@ -145,7 +147,6 @@
if (clk_users != 1)
goto exit;
if (codec_clk) {
- clk_set_rate(codec_clk, TAPAN_EXT_CLK_RATE);
clk_prepare_enable(codec_clk);
tapan_mclk_enable(codec, 1, dapm);
} else {
@@ -294,10 +295,10 @@
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
- case 0:
+ case 8000:
msm_btsco_rate = BTSCO_RATE_8KHZ;
break;
- case 1:
+ case 16000:
msm_btsco_rate = BTSCO_RATE_16KHZ;
break;
default:
@@ -309,11 +310,6 @@
return 0;
}
-static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
- SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
- msm_btsco_rate_get, msm_btsco_rate_put),
-};
-
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -548,6 +544,8 @@
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
SOC_ENUM_EXT("AUX PCM SampleRate", msm8226_auxpcm_enum[0],
msm8226_auxpcm_rate_get, msm8226_auxpcm_rate_put),
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -638,7 +636,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);
@@ -1352,6 +1350,44 @@
return 0;
}
+static bool msm8226_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->card;
+ struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_direction_output(pdata->us_euro_gpio, !value);
+
+ return true;
+}
+
+static int msm8226_setup_hs_jack(struct platform_device *pdev,
+ struct msm8226_asoc_mach_data *pdata)
+{
+ int rc;
+
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_info(&pdev->dev,
+ "property %s in node %s not found %d\n",
+ "qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name,
+ pdata->us_euro_gpio);
+ } else {
+ rc = gpio_request(pdata->us_euro_gpio,
+ "TAPAN_CODEC_US_EURO_GPIO");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: Failed to request tapan us-euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ } else {
+ mbhc_cfg.swap_gnd_mic = msm8226_swap_gnd_mic;
+ }
+ }
+ return 0;
+}
+
static __devinit int msm8226_asoc_machine_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &snd_soc_card_msm8226;
@@ -1441,6 +1477,7 @@
mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
"qcom,headset-jack-type-NO");
+ msm8226_setup_hs_jack(pdev, pdata);
ret = msm8226_prepare_codec_mclk(card);
if (ret)
@@ -1504,6 +1541,9 @@
gpio_free(pdata->mclk_gpio);
gpio_free(vdd_spkr_gpio);
+ if (pdata->us_euro_gpio > 0)
+ gpio_free(pdata->us_euro_gpio);
+
vdd_spkr_gpio = -1;
snd_soc_unregister_card(card);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index ae92ca4..a39a18b 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -19,18 +19,20 @@
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
#include <linux/regulator/consumer.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
-#include <asm/mach-types.h>
-#include <mach/socinfo.h>
#include <sound/pcm_params.h>
+#include <asm/mach-types.h>
+#include <mach/subsystem_notif.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "qdsp6v2/q6core.h"
+#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9320.h"
-#include <linux/io.h>
#define DRV_NAME "msm8974-asoc-taiko"
@@ -82,6 +84,10 @@
#define NUM_OF_AUXPCM_GPIOS 4
+static void *adsp_state_notifier;
+
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
static inline int param_is_mask(int p)
{
return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -124,6 +130,7 @@
.gpio_irq = 0,
.gpio_level_insert = 1,
.detect_extn_cable = true,
+ .micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
.insert_detect = true,
.swap_gnd_mic = NULL,
};
@@ -632,7 +639,6 @@
goto exit;
if (codec_clk) {
- clk_set_rate(codec_clk, TAIKO_EXT_CLK_RATE);
clk_prepare_enable(codec_clk);
taiko_mclk_enable(codec, 1, dapm);
} else {
@@ -856,10 +862,10 @@
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
- case 0:
+ case 8000:
msm_btsco_rate = BTSCO_RATE_8KHZ;
break;
- case 1:
+ case 16000:
msm_btsco_rate = BTSCO_RATE_16KHZ;
break;
default:
@@ -934,11 +940,6 @@
return 1;
}
-static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
- SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
- msm_btsco_rate_get, msm_btsco_rate_put),
-};
-
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1344,6 +1345,8 @@
hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
};
static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
@@ -1356,6 +1359,101 @@
return true;
}
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data;
+
+ pr_debug("%s: enter\n", __func__);
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm8974_adsp_state_callback(struct notifier_block *nb,
+ unsigned long value, void *priv)
+{
+ if (value == SUBSYS_BEFORE_SHUTDOWN) {
+ pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+ __func__);
+ msm_afe_clear_config();
+ } else if (value == SUBSYS_AFTER_POWERUP) {
+ pr_debug("%s: ADSP is up\n", __func__);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+ .notifier_call = msm8974_adsp_state_callback,
+ .priority = -INT_MAX,
+};
+
+static int msm8974_taiko_codec_up(struct snd_soc_codec *codec)
+{
+ int err;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (!q6core_is_adsp_ready()) {
+ pr_err("%s: ADSP Audio isn't ready\n", __func__);
+ } else {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ err = msm_afe_set_config(codec);
+ if (err)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, err);
+ return err;
+}
+
+static int msm8974_taiko_event_cb(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event codec_event)
+{
+ switch (codec_event) {
+ case WCD9XXX_CODEC_EVENT_CODEC_UP:
+ return msm8974_taiko_codec_up(codec);
+ break;
+ default:
+ pr_err("%s: UnSupported codec event %d\n",
+ __func__, codec_event);
+ return -EINVAL;
+ }
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -1417,19 +1515,9 @@
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
- config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
- err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ err = msm_afe_set_config(codec);
if (err) {
- pr_err("%s: Failed to set codec registers config %d\n",
- __func__, err);
- goto out;
- }
-
- config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
- err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
- if (err) {
- pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
- err);
+ pr_err("%s: Failed to set AFE config %d\n", __func__, err);
goto out;
}
@@ -1466,12 +1554,22 @@
err = taiko_hs_detect(codec, &mbhc_cfg);
if (err)
goto out;
- else
- return err;
} else {
err = -ENOMEM;
goto out;
}
+ adsp_state_notifier =
+ subsys_notif_register_notifier("adsp",
+ &adsp_state_notifier_block);
+ if (!adsp_state_notifier) {
+ pr_err("%s: Failed to register adsp state notifier\n",
+ __func__);
+ err = -EFAULT;
+ goto out;
+ }
+
+ taiko_event_register(msm8974_taiko_event_cb, rtd->codec);
+ return 0;
out:
clk_put(codec_clk);
return err;
@@ -1995,6 +2093,58 @@
/* this dainlink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
},
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
+ .ops = &msm8974_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm8974_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm8974_slimbus_2_be_ops,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -2075,21 +2225,6 @@
.be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
.ignore_suspend = 1,
},
- /* HDMI Hostless */
- {
- .name = "HDMI_RX_HOSTLESS",
- .stream_name = "HDMI_RX_HOSTLESS",
- .cpu_dai_name = "HDMI_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .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,
- .ignore_pmdown_time = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- },
/* Primary AUX PCM Backend DAI Links */
{
.name = LPASS_BE_AUXPCM_RX,
@@ -2249,19 +2384,6 @@
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
},
- {
- .name = LPASS_BE_SLIMBUS_4_TX,
- .stream_name = "Slimbus4 Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16393",
- .platform_name = "msm-pcm-hostless",
- .codec_name = "taiko_codec",
- .codec_dai_name = "taiko_vifeedback",
- .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
- .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
- .ops = &msm8974_be_ops,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ignore_suspend = 1,
- },
/* Incall Record Uplink BACK END DAI Link */
{
.name = LPASS_BE_INCALL_RECORD_TX,
@@ -2314,30 +2436,6 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
- /* Ultrasound RX Back End DAI Link */
- {
- .name = "SLIMBUS_2 Hostless Playback",
- .stream_name = "SLIMBUS_2 Hostless Playback",
- .cpu_dai_name = "msm-dai-q6-dev.16388",
- .platform_name = "msm-pcm-hostless",
- .codec_name = "taiko_codec",
- .codec_dai_name = "taiko_rx2",
- .ignore_suspend = 1,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm8974_slimbus_2_be_ops,
- },
- /* Ultrasound TX Back End DAI Link */
- {
- .name = "SLIMBUS_2 Hostless Capture",
- .stream_name = "SLIMBUS_2 Hostless Capture",
- .cpu_dai_name = "msm-dai-q6-dev.16389",
- .platform_name = "msm-pcm-hostless",
- .codec_name = "taiko_codec",
- .codec_dai_name = "taiko_tx2",
- .ignore_suspend = 1,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm8974_slimbus_2_be_ops,
- },
};
static struct snd_soc_dai_link msm8974_hdmi_dai_link[] = {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 02f6ff1..ce6cfea 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -38,6 +38,7 @@
static int msm_btsco_ch = 1;
static int msm_proxy_rx_ch = 2;
+static struct snd_soc_jack hs_jack;
#define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL 0xFE03B004
#define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR 0xFE02C000
@@ -93,16 +94,6 @@
static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
-static const struct snd_soc_dapm_route msm8x10_common_audio_map[] = {
- {"RX_BIAS", NULL, "MCLK"},
- {"INT_LDO_H", NULL, "MCLK"},
- {"MIC BIAS External", NULL, "Handset Mic"},
- {"MIC BIAS Internal2", NULL, "Headset Mic"},
- {"AMIC1", NULL, "MIC BIAS External"},
- {"AMIC2", NULL, "MIC BIAS Internal2"},
-
-};
-
static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
@@ -380,12 +371,18 @@
snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
ARRAY_SIZE(msm8x10_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, msm8x10_common_audio_map,
- ARRAY_SIZE(msm8x10_common_audio_map));
-
snd_soc_dapm_sync(dapm);
ret = msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
&digital_cdc_clk);
+
+ ret = snd_soc_jack_new(codec, "Headset Jack",
+ SND_JACK_HEADSET, &hs_jack);
+
+ if (ret) {
+ pr_err("%s: Failed to create headset jack\n", __func__);
+ return ret;
+ }
+
exit:
return ret;
}
@@ -652,7 +649,6 @@
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
- .init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
@@ -797,6 +793,10 @@
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
+ ret = snd_soc_of_parse_audio_routing(card,
+ "qcom,audio-routing");
+ if (ret)
+ goto err;
ret = snd_soc_register_card(card);
if (ret) {
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6bccdb7..a1c1aef 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -1059,7 +1059,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/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 04a0a84..b07e91e 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -64,8 +64,6 @@
struct msm_dai_q6_mi2s_dai_data {
struct msm_dai_q6_mi2s_dai_config tx_dai;
struct msm_dai_q6_mi2s_dai_config rx_dai;
- struct snd_pcm_hw_constraint_list rate_constraint;
- struct snd_pcm_hw_constraint_list bitwidth_constraint;
};
/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
@@ -1472,20 +1470,6 @@
static int msm_dai_q6_mi2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
- dev_get_drvdata(dai->dev);
-
- dev_dbg(dai->dev, "%s: cnst list %p\n", __func__,
- mi2s_dai_data->rate_constraint.list);
-
- if (mi2s_dai_data->rate_constraint.list) {
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &mi2s_dai_data->rate_constraint);
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- &mi2s_dai_data->bitwidth_constraint);
- }
return 0;
}
@@ -1659,11 +1643,25 @@
dai_data->port_config.i2s.i2s_cfg_minor_version =
AFE_API_VERSION_I2S_CONFIG;
dai_data->port_config.i2s.sample_rate = dai_data->rate;
- if (!mi2s_dai_data->rate_constraint.list) {
- mi2s_dai_data->rate_constraint.list = &dai_data->rate;
- mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
+ test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+ if ((mi2s_dai_data->tx_dai.mi2s_dai_data.rate !=
+ mi2s_dai_data->rx_dai.mi2s_dai_data.rate) ||
+ (mi2s_dai_data->rx_dai.mi2s_dai_data.bitwidth !=
+ mi2s_dai_data->tx_dai.mi2s_dai_data.bitwidth)) {
+ dev_err(dai->dev, "%s: Error mismatch in HW params\n"
+ "Tx sample_rate = %u bit_width = %hu\n"
+ "Rx sample_rate = %u bit_width = %hu\n"
+ , __func__,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.rate,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.bitwidth,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.rate,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.bitwidth);
+ return -EINVAL;
+ }
}
-
dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
"sample_rate = %u i2s_cfg_minor_version = %#x\n"
"bit_width = %hu channel_mode = %#x mono_stereo = %#x\n"
@@ -1739,14 +1737,6 @@
dev_err(dai->dev, "fail to close AFE port\n");
clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
}
-
- if (!test_bit(STATUS_PORT_STARTED,
- mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
- !test_bit(STATUS_PORT_STARTED,
- mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
- mi2s_dai_data->rate_constraint.list = NULL;
- mi2s_dai_data->bitwidth_constraint.list = NULL;
- }
}
static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
@@ -2002,8 +1992,6 @@
if (IS_ERR_VALUE(rc))
goto free_dai;
- dai_data->rate_constraint.count = 1;
- dai_data->bitwidth_constraint.count = 1;
rc = snd_soc_register_dai(&pdev->dev, mi2s_dai);
if (IS_ERR_VALUE(rc))
goto err_register;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 363fb15..f76d455 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -117,8 +117,8 @@
if (copy_from_user(prtd->lsm_client->sound_model.data,
snd_model.data, snd_model.data_size)) {
- pr_err("%s: copy from user data failed size %d\n",
- __func__, snd_model.data_size);
+ pr_err("%s: copy from user data failed data %p size %d\n",
+ __func__, snd_model.data, snd_model.data_size);
rc = -EFAULT;
break;
}
@@ -128,9 +128,12 @@
snd_model.min_keyw_confidence,
snd_model.min_user_confidence,
snd_model.detect_failure);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s: q6lsm_register_sound_model failed =%d\n",
__func__, rc);
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+ }
+
break;
case SNDRV_LSM_DEREG_SND_MODEL:
@@ -213,11 +216,10 @@
pr_debug("%s: Stopping LSM client session\n", __func__);
if (prtd->lsm_client->started) {
ret = q6lsm_stop(prtd->lsm_client, true);
- if (!ret) {
- prtd->lsm_client->started = false;
- pr_debug("%s: LSM client session stopped\n",
- __func__);
- }
+ if (!ret)
+ pr_debug("%s: LSM client session stopped %d\n",
+ __func__, ret);
+ prtd->lsm_client->started = false;
}
break;
@@ -258,10 +260,10 @@
}
ret = q6lsm_open(prtd->lsm_client);
if (ret < 0) {
- pr_err("%s: lsm out open failed\n", __func__);
+ pr_err("%s: lsm open failed, %d\n", __func__, ret);
q6lsm_client_free(prtd->lsm_client);
kfree(prtd);
- return -ENOMEM;
+ return ret;
}
pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index a078042..4297ddb 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -454,7 +454,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;
}
@@ -507,7 +507,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,
@@ -546,7 +546,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/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 9899f97..4459bc8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -364,7 +364,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;
}
@@ -573,7 +573,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/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 0592d10..461fca4 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -295,7 +295,7 @@
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
pr_debug("%s: Trigger start\n", __func__);
- q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
@@ -303,12 +303,12 @@
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
break;
prtd->cmd_ack = 0;
- q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
- q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
atomic_set(&prtd->start, 0);
break;
default:
@@ -410,7 +410,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;
}
@@ -470,7 +470,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,
@@ -509,7 +509,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/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index d7148f1..4fd90f9 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -58,6 +58,7 @@
static int srs_alsa_ctrl_ever_called;
static int lsm_mux_slim_port;
static int slim0_rx_aanc_fb_port;
+static int msm_route_ec_ref_rx = 3; /* NONE */
enum {
MADNONE,
@@ -617,7 +618,7 @@
static void msm_pcm_routing_process_voice(u16 reg, u16 val, int set)
{
- u16 session_id = 0;
+ u32 session_id = 0;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -1347,6 +1348,51 @@
return 0;
}
+static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ec_ref_rx = %d", __func__, msm_route_ec_ref_rx);
+ ucontrol->value.integer.value[0] = msm_route_ec_ref_rx;
+ return 0;
+}
+
+static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ec_ref_port_id;
+ mutex_lock(&routing_lock);
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm_route_ec_ref_rx = 0;
+ ec_ref_port_id = SLIMBUS_0_RX;
+ break;
+ case 1:
+ msm_route_ec_ref_rx = 1;
+ ec_ref_port_id = PRIMARY_I2S_RX;
+ break;
+ default:
+ msm_route_ec_ref_rx = 3; /* NONE */
+ ec_ref_port_id = -1;
+ break;
+ }
+ adm_ec_ref_rx_id(ec_ref_port_id);
+ pr_debug("%s: msm_route_ec_ref_rx = %d\n",
+ __func__, msm_route_ec_ref_rx);
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PROXY_RX",
+ "NONE" };
+static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
+ SOC_ENUM_SINGLE_EXT(4, ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new ec_ref_rx_mixer_controls[] = {
+ SOC_ENUM_EXT("EC_REF_RX", msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
+};
+
static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1897,6 +1943,9 @@
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2161,6 +2210,15 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -2179,6 +2237,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_port_mixer_controls[] = {
@@ -2217,6 +2278,9 @@
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_port_mixer_controls[] = {
@@ -3192,6 +3256,7 @@
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3213,12 +3278,14 @@
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3310,6 +3377,7 @@
{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"SLIMBUS_0_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
{"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
@@ -3326,7 +3394,10 @@
{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"Voice Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"Voice Stub Tx Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3340,6 +3411,7 @@
{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
{"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
{"SLIMBUS_3_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
@@ -3664,6 +3736,9 @@
dolby_dap_param_end_point_controls,
ARRAY_SIZE(dolby_dap_param_end_point_controls));
+ snd_soc_add_platform_controls(platform,
+ ec_ref_rx_mixer_controls,
+ ARRAY_SIZE(ec_ref_rx_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 5485440..5c97403 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -67,9 +67,9 @@
return false;
}
-static uint16_t get_session_id(struct msm_voice *pvoc)
+static uint32_t get_session_id(struct msm_voice *pvoc)
{
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
if (is_volte(pvoc))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
@@ -175,7 +175,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_voice *prtd = runtime->private_data;
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
int ret = 0;
mutex_lock(&prtd->lock);
@@ -201,7 +201,7 @@
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_voice *prtd = runtime->private_data;
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
mutex_lock(&prtd->lock);
@@ -236,7 +236,7 @@
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_voice *prtd = runtime->private_data;
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
pr_debug("%s: cmd = %d\n", __func__, cmd);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 5f9d4db..bdb0e13 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -55,6 +55,7 @@
atomic_t mem_map_cal_index;
int set_custom_topology;
+ int ec_ref_rx;
};
static struct adm_ctl this_adm;
@@ -965,7 +966,13 @@
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
- open.endpoint_id_2 = 0xFFFF;
+
+ if (this_adm.ec_ref_rx == -1) {
+ open.endpoint_id_2 = 0xFFFF;
+ } else if (this_adm.ec_ref_rx && (path != 1)) {
+ open.endpoint_id_2 = this_adm.ec_ref_rx;
+ this_adm.ec_ref_rx = -1;
+ }
open.topology_id = topology;
if ((open.topology_id == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
@@ -1366,6 +1373,12 @@
return atomic_read(&this_adm.copp_id[port_index]);
}
+void adm_ec_ref_rx_id(int port_id)
+{
+ this_adm.ec_ref_rx = port_id;
+ pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+}
+
int adm_close(int port_id, bool perf_mode)
{
struct apr_hdr close;
@@ -1471,6 +1484,7 @@
int i = 0;
this_adm.apr = NULL;
this_adm.set_custom_topology = 1;
+ this_adm.ec_ref_rx = -1;
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 6615940..9882ec7 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -50,6 +50,7 @@
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+static unsigned long afe_configured_cmd;
static struct afe_ctl this_afe;
@@ -392,11 +393,23 @@
if ((this_afe.afe_cal_addr[path].cal_paddr != cal_block.cal_paddr) ||
(cal_block.cal_size > this_afe.afe_cal_addr[path].cal_size)) {
atomic_set(&this_afe.mem_map_cal_index, path);
- if (this_afe.afe_cal_addr[path].cal_paddr != 0)
- afe_cmd_memory_unmap(
+ if (this_afe.afe_cal_addr[path].cal_paddr != 0) {
+ result = afe_cmd_memory_unmap(
this_afe.afe_cal_addr[path].cal_paddr);
+ if (result) {
+ pr_err("%s: AFE memory unmap failed\n",
+ __func__);
+ atomic_set(&this_afe.mem_map_cal_index, -1);
+ goto done;
+ }
+ }
- afe_cmd_memory_map(cal_block.cal_paddr, size);
+ result = afe_cmd_memory_map(cal_block.cal_paddr, size);
+ if (result) {
+ pr_err("%s: AFE memory map failed\n", __func__);
+ atomic_set(&this_afe.mem_map_cal_index, -1);
+ goto done;
+ }
atomic_set(&this_afe.mem_map_cal_index, -1);
this_afe.afe_cal_addr[path].cal_paddr = cal_block.cal_paddr;
this_afe.afe_cal_addr[path].cal_size = size;
@@ -1053,10 +1066,28 @@
ret = -EINVAL;
}
+ if (!ret)
+ set_bit(config_type, &afe_configured_cmd);
+
pr_debug("%s: leave ret %d\n", __func__, ret);
return ret;
}
+/*
+ * afe_clear_config - If SSR happens ADSP loses AFE configs, let AFE driver know
+ * about the state so client driver can wait until AFE is
+ * reconfigured.
+ */
+void afe_clear_config(enum afe_config_type config)
+{
+ clear_bit(config, &afe_configured_cmd);
+}
+
+bool afe_has_config(enum afe_config_type config)
+{
+ return !!test_bit(config, &afe_configured_cmd);
+}
+
static int afe_send_cmd_port_start(u16 port_id)
{
struct afe_port_cmd_device_start start;
@@ -1930,6 +1961,7 @@
pr_debug("%s: dma_addr_p 0x%x , size %d\n", __func__,
dma_addr_p, dma_buf_sz);
atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
this_afe.mmap_handle = 0;
ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
if (ret < 0) {
@@ -1947,6 +1979,12 @@
ret = -EINVAL;
goto fail_cmd;
}
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: Memory map cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
pr_debug("%s: mmap handle 0x%x\n", __func__, this_afe.mmap_handle);
kfree(mmap_region_cmd);
return 0;
@@ -2101,10 +2139,16 @@
/* Todo */
index = mregion.hdr.token = IDX_RSVD_2;
+ atomic_set(&this_afe.status, 0);
ret = afe_apr_send_pkt(&mregion, &this_afe.wait[index]);
if (ret)
pr_err("%s: AFE memory unmap cmd failed %d\n",
__func__, ret);
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: Memory unmap cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+
return ret;
}
@@ -2539,7 +2583,7 @@
ret = wait_event_timeout(this_afe.wait[index],
(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/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ac26d0c..46d208b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -408,7 +408,7 @@
result = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0), 5*HZ);
- if (result < 0) {
+ if (!result) {
pr_err("%s: Set topologies failed payload = 0x%x\n",
__func__, cal_block.cal_paddr);
goto done;
@@ -508,16 +508,17 @@
int q6asm_mmap_apr_dereg(void)
{
- if (atomic_read(&this_mmap.ref_cnt) <= 0) {
- pr_err("%s: APR Common Port Already Closed\n", __func__);
- goto done;
- }
- atomic_dec(&this_mmap.ref_cnt);
- if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ int c;
+
+ c = atomic_sub_return(1, &this_mmap.ref_cnt);
+ if (c == 0) {
apr_deregister(this_mmap.apr);
- pr_debug("%s:APR De-Register common port\n", __func__);
+ pr_debug("%s: APR De-Register common port\n", __func__);
+ } else if (c < 0) {
+ pr_err("%s: APR Common Port Already Closed\n", __func__);
+ atomic_set(&this_mmap.ref_cnt, 0);
}
-done:
+
return 0;
}
@@ -578,7 +579,8 @@
void *q6asm_mmap_apr_reg(void)
{
- if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
+ (this_mmap.apr == NULL)) {
this_mmap.apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_mmapcallback,\
0x0FFFFFFFF, &this_mmap);
@@ -1715,12 +1717,14 @@
run.time_lsw = lsw_ts;
run.time_msw = msw_ts;
+ /* have to increase first avoid race */
+ atomic_inc(&ac->nowait_cmd_cnt);
rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
if (rc < 0) {
+ atomic_dec(&ac->nowait_cmd_cnt);
pr_err("%s:Commmand run failed[%d]", __func__, rc);
return -EINVAL;
}
- atomic_inc(&ac->nowait_cmd_cnt);
return 0;
}
@@ -3691,12 +3695,14 @@
pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
ac->session,
hdr.opcode);
+ /* have to increase first avoid race */
+ atomic_inc(&ac->nowait_cmd_cnt);
rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
if (rc < 0) {
+ atomic_dec(&ac->nowait_cmd_cnt);
pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
goto fail_cmd;
}
- atomic_inc(&ac->nowait_cmd_cnt);
return 0;
fail_cmd:
return -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 5fec0c1..e9352df 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -30,6 +30,7 @@
wait_queue_head_t bus_bw_req_wait;
u32 bus_bw_resp_received;
struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
+ u32 param;
};
static struct q6core_str q6core_lcl;
@@ -102,6 +103,17 @@
break;
}
+ case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
+ payload1 = data->payload;
+ q6core_lcl.param = payload1[0];
+ pr_debug("%s: Received ADSP get state response 0x%x\n",
+ __func__, q6core_lcl.param);
+ /* ensure .param is updated prior to .bus_bw_resp_received */
+ wmb();
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+
default:
pr_err("Message id from adsp core svc: %d\n", data->opcode);
break;
@@ -197,6 +209,39 @@
return ret;
}
+bool q6core_is_adsp_ready(void)
+{
+ int rc;
+ bool ret = false;
+ struct apr_hdr hdr;
+
+ pr_debug("%s: enter\n", __func__);
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
+ hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
+
+ ocm_core_open();
+ q6core_lcl.bus_bw_resp_received = 0;
+ rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+ if (rc < 0) {
+ pr_err("%s: Get ADSP state APR packet send event\n", __func__);
+ goto bail;
+ }
+
+ rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+ /* ensure to read updated param by callback thread */
+ rmb();
+ ret = !!q6core_lcl.param;
+ }
+bail:
+ pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
+ return ret;
+}
static int __init core_init(void)
{
diff --git a/sound/soc/msm/qdsp6v2/q6core.h b/sound/soc/msm/qdsp6v2/q6core.h
index 39bf4ab..e5a59bc 100644
--- a/sound/soc/msm/qdsp6v2/q6core.h
+++ b/sound/soc/msm/qdsp6v2/q6core.h
@@ -25,6 +25,9 @@
#define AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO 0x00012904
+#define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C
+#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D
+
/* @brief AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO payload
* structure. Payload for this event comprises one instance of
* avcs_cmd_rsp_get_low_power_segments_info_t, followed
@@ -89,6 +92,7 @@
int core_get_low_power_segments(
struct avcs_cmd_rsp_get_low_power_segments_info_t **);
+bool q6core_is_adsp_ready(void);
#define ADSP_CMD_SET_DOLBY_MANUFACTURER_ID 0x00012918
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 49e5ede..c5483ee 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -31,6 +31,7 @@
#include <mach/memory.h>
#include <mach/debug_mm.h>
#include "audio_acdb.h"
+#include "q6core.h"
#define APR_TIMEOUT (5 * HZ)
#define LSM_CAL_SIZE 4096
@@ -70,7 +71,6 @@
static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
static int q6lsm_send_cal(struct lsm_client *client);
-static int q6lsm_snd_model_buf_free(struct lsm_client *client);
static int q6lsm_callback(struct apr_client_data *data, void *priv)
{
@@ -83,6 +83,13 @@
return -EINVAL;
}
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
+ __func__, data->opcode, data->reset_event,
+ data->reset_proc);
+ return 0;
+ }
+
payload = data->payload;
pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
__func__, client->session,
@@ -311,6 +318,13 @@
int rc;
struct lsm_stream_cmd_open_tx open;
+ if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+ !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+ pr_err("%s: AFE isn't configured yet\n", __func__);
+ rc = -EAGAIN;
+ goto exit;
+ }
+
memset(&open, 0, sizeof(open));
q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
@@ -323,6 +337,7 @@
pr_err("%s: Open failed opcode 0x%x, rc %d\n",
__func__, open.hdr.opcode, rc);
+exit:
pr_debug("%s: leave %d\n", __func__, rc);
return rc;
}
@@ -461,9 +476,10 @@
cmd.hdr.opcode, rc);
} else {
pr_debug("%s: Deregister sound model succeeded\n", __func__);
- q6lsm_snd_model_buf_free(client);
}
+ q6lsm_snd_model_buf_free(client);
+
return rc;
}
@@ -493,8 +509,8 @@
int rc;
int cmd_size = 0;
- pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
- __func__, dma_addr_p, dma_buf_sz, client->session);
+ pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
+ __func__, dma_addr_p, dma_buf_sz, mmap_p, client->session);
cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
sizeof(struct avs_shared_map_region_payload);
@@ -530,6 +546,29 @@
return rc;
}
+static int q6lsm_memory_unmap_regions(struct lsm_client *client,
+ uint32_t handle)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap;
+ int rc = 0;
+ int cmd_size = 0;
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+ q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+ true, (client->session << 8));
+ unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap.mem_map_handle = handle;
+
+ pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+ NULL);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+ __func__, unmap.hdr.opcode, rc);
+
+ return rc;
+}
+
static int q6lsm_send_cal(struct lsm_client *client)
{
int rc;
@@ -550,15 +589,20 @@
/* Cache mmap address, only map once or if new addr */
if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
(lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
- if (lsm_common.lsm_cal_addr != 0)
- afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+ if (lsm_common.lsm_cal_addr != 0) {
+ rc = q6lsm_memory_unmap_regions(client,
+ lsm_common.mmap_handle_for_cal);
+ if (rc)
+ pr_warn("%s: Unmapping %x failed, %d\n",
+ __func__, lsm_common.lsm_cal_addr, rc);
+ }
rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
LSM_CAL_SIZE,
&lsm_common.mmap_handle_for_cal);
if (rc < 0) {
- pr_err("%s: Calibration data memory map failed\n",
- __func__);
+ pr_err("%s: Calibration data memory map failed, %d\n",
+ __func__, rc);
goto bail;
}
lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
@@ -582,38 +626,18 @@
return rc;
}
-static int q6lsm_memory_unmap_regions(struct lsm_client *client)
-{
- struct avs_cmd_shared_mem_unmap_regions unmap;
- int rc = 0;
- int cmd_size = 0;
-
- cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
- q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
- true, (client->session << 8));
- unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
- unmap.mem_map_handle = client->sound_model.mem_map_handle;
-
- pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
- rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
- NULL);
- if (rc)
- pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
- __func__, unmap.hdr.opcode, rc);
-
- return rc;
-}
-
-static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+int q6lsm_snd_model_buf_free(struct lsm_client *client)
{
int rc;
pr_debug("%s: Session id %d\n", __func__, client->session);
mutex_lock(&client->cmd_lock);
- rc = q6lsm_memory_unmap_regions(client);
- if (rc < 0) {
+ rc = q6lsm_memory_unmap_regions(client,
+ client->sound_model.mem_map_handle);
+ if (rc < 0)
pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
- } else if (client->sound_model.data) {
+
+ if (client->sound_model.data) {
ion_unmap_kernel(client->sound_model.client,
client->sound_model.handle);
ion_free(client->sound_model.client,
@@ -649,12 +673,22 @@
static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
{
unsigned long flags;
- uint32_t sid = 0;
+ uint32_t command;
+ uint32_t retcode;
+ uint32_t sid;
const uint32_t *payload = data->payload;
- const uint32_t command = payload[0];
- const uint32_t retcode = payload[1];
struct lsm_client *client = NULL;
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
+ __func__, data->opcode, data->reset_event,
+ data->reset_proc);
+ lsm_common.lsm_cal_addr = 0;
+ return 0;
+ }
+
+ command = payload[0];
+ retcode = payload[1];
pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
data->opcode, command, retcode);
@@ -710,6 +744,7 @@
if (IS_ERR_OR_NULL(client->sound_model.client)) {
pr_err("%s: ION create client for AUDIO failed\n",
__func__);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
client->sound_model.handle =
@@ -718,6 +753,7 @@
if (IS_ERR_OR_NULL(client->sound_model.handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
@@ -728,6 +764,7 @@
if (rc) {
pr_err("%s: ION get physical mem failed, rc%d\n",
__func__, rc);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
@@ -736,6 +773,7 @@
client->sound_model.handle);
if (IS_ERR_OR_NULL(client->sound_model.data)) {
pr_err("%s: ION memory mapping failed\n", __func__);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
memset(client->sound_model.data, 0, len);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 26d9d48..2fabca1 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -56,12 +56,12 @@
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
static int voice_send_vol_index_cmd(struct voice_data *v);
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
- unsigned int bufcnt);
+ uint32_t mem_handle);
static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
static int voice_send_mvm_media_type_cmd(struct voice_data *v);
static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v);
-static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+static int voice_set_packet_exchange_mode_and_config(uint32_t session_id,
uint32_t mode);
static int voice_send_cvs_register_cal_cmd(struct voice_data *v);
@@ -85,6 +85,9 @@
static int voice_send_set_pp_enable_cmd(struct voice_data *v,
uint32_t module_id, int enable);
+static struct voice_data *voice_get_session_by_idx(int idx);
+static int voice_get_idx_for_session(u32 session_id);
+
static u16 voice_get_mvm_handle(struct voice_data *v)
{
if (v == NULL) {
@@ -154,7 +157,7 @@
v->cvp_handle = cvp_handle;
}
-char *voc_get_session_name(u16 session_id)
+char *voc_get_session_name(u32 session_id)
{
char *session_name = NULL;
@@ -169,9 +172,9 @@
return session_name;
}
-uint16_t voc_get_session_id(char *name)
+uint32_t voc_get_session_id(char *name)
{
- u16 session_id = 0;
+ u32 session_id = 0;
if (name != NULL) {
if (!strncmp(name, "Voice session", 13))
@@ -192,41 +195,132 @@
return session_id;
}
-static struct voice_data *voice_get_session(u16 session_id)
+static struct voice_data *voice_get_session(u32 session_id)
{
struct voice_data *v = NULL;
- if ((session_id >= SESSION_ID_BASE) &&
- (session_id < SESSION_ID_BASE + MAX_VOC_SESSIONS)) {
- v = &common.voice[session_id - SESSION_ID_BASE];
+ switch (session_id) {
+ case VOICE_SESSION_VSID:
+ v = &common.voice[VOC_PATH_PASSIVE];
+ break;
+
+ case VOICE2_SESSION_VSID:
+ v = &common.voice[VOC_PATH_VOICE2_PASSIVE];
+ break;
+
+ case VOLTE_SESSION_VSID:
+ v = &common.voice[VOC_PATH_VOLTE_PASSIVE];
+ break;
+
+ case VOIP_SESSION_VSID:
+ v = &common.voice[VOC_PATH_FULL];
+ break;
+
+ case ALL_SESSION_VSID:
+ break;
+
+ default:
+ pr_err("%s: Invalid session_id : %x\n", __func__, session_id);
+
+ break;
}
- pr_debug("%s: session_id 0x%x session handle 0x%x\n",
- __func__, session_id, (unsigned int)v);
+ pr_debug("%s:session_id 0x%x session handle 0x%x\n",
+ __func__, session_id, (unsigned int)v);
return v;
}
-static bool is_voice_session(u16 session_id)
+static int voice_get_idx_for_session(u32 session_id)
+{
+ int idx = 0;
+
+ switch (session_id) {
+ case VOICE_SESSION_VSID:
+ idx = VOC_PATH_PASSIVE;
+ break;
+
+ case VOICE2_SESSION_VSID:
+ idx = VOC_PATH_VOICE2_PASSIVE;
+ break;
+
+ case VOLTE_SESSION_VSID:
+ idx = VOC_PATH_VOLTE_PASSIVE;
+ break;
+
+ case VOIP_SESSION_VSID:
+ idx = VOC_PATH_FULL;
+ break;
+
+ case ALL_SESSION_VSID:
+ idx = MAX_VOC_SESSIONS - 1;
+ break;
+
+ default:
+ pr_err("%s: Invalid session_id : %x\n", __func__, session_id);
+
+ break;
+ }
+
+ return idx;
+}
+
+static struct voice_data *voice_get_session_by_idx(int idx)
+{
+ return ((idx < 0 || idx >= MAX_VOC_SESSIONS) ?
+ NULL : &common.voice[idx]);
+}
+
+static bool is_voice_session(u32 session_id)
{
return (session_id == common.voice[VOC_PATH_PASSIVE].session_id);
}
-static bool is_voip_session(u16 session_id)
+static bool is_voip_session(u32 session_id)
{
return (session_id == common.voice[VOC_PATH_FULL].session_id);
}
-static bool is_volte_session(u16 session_id)
+static bool is_volte_session(u32 session_id)
{
return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
}
-static bool is_voice2_session(u16 session_id)
+static bool is_voice2_session(u32 session_id)
{
return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
}
+static bool is_other_session_active(u32 session_id)
+{
+ int i;
+ bool ret = false;
+
+ /* Check if there is other active session except the input one */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ if (common.voice[i].session_id == session_id)
+ continue;
+
+ if ((common.voice[i].voc_state == VOC_RUN) ||
+ (common.voice[i].voc_state == VOC_CHANGE) ||
+ (common.voice[i].voc_state == VOC_STANDBY)) {
+ ret = true;
+ break;
+ }
+ }
+ pr_debug("%s: ret %d\n", __func__, ret);
+
+ return ret;
+}
+
+static void init_session_id(void)
+{
+ common.voice[VOC_PATH_PASSIVE].session_id = VOICE_SESSION_VSID;
+ common.voice[VOC_PATH_VOLTE_PASSIVE].session_id = VOLTE_SESSION_VSID;
+ common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
+ common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
+}
+
static int voice_apr_register(void)
{
void *modem_mvm, *modem_cvs, *modem_cvp;
@@ -364,7 +458,8 @@
APR_HDR_SIZE);
pr_debug("%s: send mvm Voice Ctl pkt size = %d\n",
__func__, mvm_voice_ctl_cmd.hdr.pkt_size);
- mvm_voice_ctl_cmd.hdr.src_port = v->session_id;
+ mvm_voice_ctl_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_voice_ctl_cmd.hdr.dest_port = mvm_handle;
mvm_voice_ctl_cmd.hdr.token = 0;
mvm_voice_ctl_cmd.hdr.opcode =
@@ -438,7 +533,8 @@
APR_HDR_SIZE);
pr_debug("%s: send mvm create session pkt size = %d\n",
__func__, mvm_session_cmd.hdr.pkt_size);
- mvm_session_cmd.hdr.src_port = v->session_id;
+ mvm_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_session_cmd.hdr.dest_port = 0;
mvm_session_cmd.hdr.token = 0;
mvm_session_cmd.hdr.opcode =
@@ -449,7 +545,7 @@
sizeof(mvm_session_cmd.mvm_session.name));
} else if (is_voice2_session(v->session_id)) {
strlcpy(mvm_session_cmd.mvm_session.name,
- VOICE2_SESSION_VSID,
+ VOICE2_SESSION_VSID_STR,
sizeof(mvm_session_cmd.mvm_session.name));
} else {
strlcpy(mvm_session_cmd.mvm_session.name,
@@ -482,7 +578,8 @@
APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_session_cmd) -
APR_HDR_SIZE);
- mvm_session_cmd.hdr.src_port = v->session_id;
+ mvm_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_session_cmd.hdr.dest_port = 0;
mvm_session_cmd.hdr.token = 0;
mvm_session_cmd.hdr.opcode =
@@ -526,7 +623,8 @@
APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_session_cmd) -
APR_HDR_SIZE);
- cvs_session_cmd.hdr.src_port = v->session_id;
+ cvs_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_session_cmd.hdr.dest_port = 0;
cvs_session_cmd.hdr.token = 0;
cvs_session_cmd.hdr.opcode =
@@ -537,7 +635,7 @@
sizeof(cvs_session_cmd.cvs_session.name));
} else if (is_voice2_session(v->session_id)) {
strlcpy(cvs_session_cmd.cvs_session.name,
- VOICE2_SESSION_VSID,
+ VOICE2_SESSION_VSID_STR,
sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
@@ -575,7 +673,8 @@
sizeof(cvs_full_ctl_cmd) -
APR_HDR_SIZE);
- cvs_full_ctl_cmd.hdr.src_port = v->session_id;
+ cvs_full_ctl_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_full_ctl_cmd.hdr.dest_port = 0;
cvs_full_ctl_cmd.hdr.token = 0;
cvs_full_ctl_cmd.hdr.opcode =
@@ -622,7 +721,8 @@
APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(attach_stream_cmd) -
APR_HDR_SIZE);
- attach_stream_cmd.hdr.src_port = v->session_id;
+ attach_stream_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
attach_stream_cmd.hdr.dest_port = mvm_handle;
attach_stream_cmd.hdr.token = 0;
attach_stream_cmd.hdr.opcode =
@@ -676,7 +776,7 @@
cvs_handle = voice_get_cvs_handle(v);
/* MVM, CVS sessions are destroyed only for Full control sessions. */
- if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+ if (is_voip_session(v->session_id)) {
pr_debug("%s: MVM detach stream, VOC_STATE: %d\n", __func__,
v->voc_state);
@@ -687,7 +787,8 @@
APR_PKT_VER);
detach_stream.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(detach_stream) - APR_HDR_SIZE);
- detach_stream.hdr.src_port = v->session_id;
+ detach_stream.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
detach_stream.hdr.dest_port = mvm_handle;
detach_stream.hdr.token = 0;
detach_stream.hdr.opcode = VSS_IMVM_CMD_DETACH_STREAM;
@@ -698,6 +799,7 @@
if (ret < 0) {
pr_err("%s: Error %d sending DETACH_STREAM\n",
__func__, ret);
+
goto fail;
}
ret = wait_event_timeout(v->mvm_wait,
@@ -705,9 +807,25 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait event timeout\n", __func__);
+
goto fail;
}
+ /* Unmap memory */
+ if (v->shmem_info.mem_handle != 0) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ v->shmem_info.mem_handle);
+ if (ret < 0) {
+ pr_err("%s Memory_unmap for voip failed %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ v->shmem_info.mem_handle = 0;
+ }
+ }
+
+ if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -716,7 +834,8 @@
APR_PKT_VER);
cvs_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_destroy) - APR_HDR_SIZE);
- cvs_destroy.src_port = v->session_id;
+ cvs_destroy.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_destroy.dest_port = cvs_handle;
cvs_destroy.token = 0;
cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
@@ -726,6 +845,7 @@
if (ret < 0) {
pr_err("%s: Error %d sending CVS DESTROY\n",
__func__, ret);
+
goto fail;
}
ret = wait_event_timeout(v->cvs_wait,
@@ -739,11 +859,21 @@
cvs_handle = 0;
voice_set_cvs_handle(v, cvs_handle);
- ret = voice_send_mvm_unmap_memory_physical_cmd(v,
- NUM_OF_BUFFERS);
- if (ret < 0) {
- pr_err("%s CMD Memory_unmap_regions failed %d\n",
- __func__, ret);
+ /* Unmap physical memory for calibration */
+ pr_debug("%s: cal_mem_handle %d\n", __func__,
+ common.cal_mem_handle);
+
+ if (!is_other_session_active(v->session_id) &&
+ (common.cal_mem_handle != 0)) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ common.cal_mem_handle);
+ if (ret < 0) {
+ pr_err("%s Fail at cal mem unmap %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ common.cal_mem_handle = 0;
}
/* Destroy MVM. */
@@ -754,7 +884,8 @@
APR_PKT_VER);
mvm_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_destroy) - APR_HDR_SIZE);
- mvm_destroy.src_port = v->session_id;
+ mvm_destroy.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_destroy.dest_port = mvm_handle;
mvm_destroy.token = 0;
mvm_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
@@ -813,7 +944,8 @@
APR_HDR_SIZE);
pr_debug("%s: pkt size = %d\n",
__func__, mvm_tty_mode_cmd.hdr.pkt_size);
- mvm_tty_mode_cmd.hdr.src_port = v->session_id;
+ mvm_tty_mode_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
mvm_tty_mode_cmd.hdr.token = 0;
mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
@@ -866,7 +998,7 @@
cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_set_pp_cmd) -
APR_HDR_SIZE);
- cvs_set_pp_cmd.hdr.src_port = v->session_id;
+ cvs_set_pp_cmd.hdr.src_port = voice_get_idx_for_session(v->session_id);
cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
cvs_set_pp_cmd.hdr.token = 0;
cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
@@ -924,7 +1056,8 @@
APR_PKT_VER);
cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_set_dtx) - APR_HDR_SIZE);
- cvs_set_dtx.hdr.src_port = v->session_id;
+ cvs_set_dtx.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_set_dtx.hdr.dest_port = cvs_handle;
cvs_set_dtx.hdr.token = 0;
cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
@@ -977,7 +1110,8 @@
mvm_set_cal_media_type.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_set_cal_media_type) -
APR_HDR_SIZE);
- mvm_set_cal_media_type.hdr.src_port = v->session_id;
+ mvm_set_cal_media_type.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_set_cal_media_type.hdr.dest_port = mvm_handle;
mvm_set_cal_media_type.hdr.token = 0;
mvm_set_cal_media_type.hdr.opcode = VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE;
@@ -1033,7 +1167,8 @@
cvs_dtmf_rx_detection.hdr.pkt_size =
APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_dtmf_rx_detection) - APR_HDR_SIZE);
- cvs_dtmf_rx_detection.hdr.src_port = v->session_id;
+ cvs_dtmf_rx_detection.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_dtmf_rx_detection.hdr.dest_port = cvs_handle;
cvs_dtmf_rx_detection.hdr.token = 0;
cvs_dtmf_rx_detection.hdr.opcode =
@@ -1079,7 +1214,7 @@
}
}
-int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable)
+int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -1130,7 +1265,8 @@
cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_set_media_cmd) -
APR_HDR_SIZE);
- cvs_set_media_cmd.hdr.src_port = v->session_id;
+ cvs_set_media_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_set_media_cmd.hdr.dest_port = cvs_handle;
cvs_set_media_cmd.hdr.token = 0;
cvs_set_media_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MEDIA_TYPE;
@@ -1169,7 +1305,8 @@
APR_PKT_VER);
cvs_set_cdma_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_set_cdma_rate) - APR_HDR_SIZE);
- cvs_set_cdma_rate.hdr.src_port = v->session_id;
+ cvs_set_cdma_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_set_cdma_rate.hdr.dest_port = cvs_handle;
cvs_set_cdma_rate.hdr.token = 0;
cvs_set_cdma_rate.hdr.opcode =
@@ -1206,7 +1343,8 @@
APR_PKT_VER);
cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
- cvs_set_amr_rate.hdr.src_port = v->session_id;
+ cvs_set_amr_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_set_amr_rate.hdr.dest_port = cvs_handle;
cvs_set_amr_rate.hdr.token = 0;
cvs_set_amr_rate.hdr.opcode =
@@ -1247,7 +1385,8 @@
cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_set_amrwb_rate) -
APR_HDR_SIZE);
- cvs_set_amrwb_rate.hdr.src_port = v->session_id;
+ cvs_set_amrwb_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
cvs_set_amrwb_rate.hdr.token = 0;
cvs_set_amrwb_rate.hdr.opcode =
@@ -1319,7 +1458,8 @@
sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
pr_debug("send mvm_start_voice_cmd pkt size = %d\n",
mvm_start_voice_cmd.pkt_size);
- mvm_start_voice_cmd.src_port = v->session_id;
+ mvm_start_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_start_voice_cmd.dest_port = mvm_handle;
mvm_start_voice_cmd.token = 0;
mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
@@ -1369,7 +1509,8 @@
sizeof(cvp_disable_cmd) - APR_HDR_SIZE);
pr_debug("cvp_disable_cmd pkt size = %d, cvp_handle=%d\n",
cvp_disable_cmd.pkt_size, cvp_handle);
- cvp_disable_cmd.src_port = v->session_id;
+ cvp_disable_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_disable_cmd.dest_port = cvp_handle;
cvp_disable_cmd.token = 0;
cvp_disable_cmd.opcode = VSS_IVOCPROC_CMD_DISABLE;
@@ -1448,7 +1589,8 @@
sizeof(cvp_setdev_cmd) - APR_HDR_SIZE);
pr_debug(" send create cvp setdev, pkt size = %d\n",
cvp_setdev_cmd.hdr.pkt_size);
- cvp_setdev_cmd.hdr.src_port = v->session_id;
+ cvp_setdev_cmd.hdr.src_port =
+ voice_get_idx_for_session(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_V2;
@@ -1514,7 +1656,8 @@
sizeof(mvm_stop_voice_cmd) - APR_HDR_SIZE);
pr_debug("send mvm_stop_voice_cmd pkt size = %d\n",
mvm_stop_voice_cmd.pkt_size);
- mvm_stop_voice_cmd.src_port = v->session_id;
+ mvm_stop_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_stop_voice_cmd.dest_port = mvm_handle;
mvm_stop_voice_cmd.token = 0;
mvm_stop_voice_cmd.opcode = VSS_IMVM_CMD_STOP_VOICE;
@@ -1574,7 +1717,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvs_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_reg_cal_cmd) - APR_HDR_SIZE);
- cvs_reg_cal_cmd.hdr.src_port = v->session_id;
+ cvs_reg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_reg_cal_cmd.hdr.dest_port = voice_get_cvs_handle(v);
cvs_reg_cal_cmd.hdr.token = 0;
cvs_reg_cal_cmd.hdr.opcode =
@@ -1639,7 +1783,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvs_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_dereg_cal_cmd) - APR_HDR_SIZE);
- cvs_dereg_cal_cmd.hdr.src_port = v->session_id;
+ cvs_dereg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_dereg_cal_cmd.hdr.dest_port = voice_get_cvs_handle(v);
cvs_dereg_cal_cmd.hdr.token = 0;
cvs_dereg_cal_cmd.hdr.opcode =
@@ -1704,7 +1849,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvp_reg_dev_cfg_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_reg_dev_cfg_cmd) - APR_HDR_SIZE);
- cvp_reg_dev_cfg_cmd.hdr.src_port = v->session_id;
+ cvp_reg_dev_cfg_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_reg_dev_cfg_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_reg_dev_cfg_cmd.hdr.token = 0;
cvp_reg_dev_cfg_cmd.hdr.opcode =
@@ -1766,7 +1912,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvp_dereg_dev_cfg_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_dereg_dev_cfg_cmd) - APR_HDR_SIZE);
- cvp_dereg_dev_cfg_cmd.hdr.src_port = v->session_id;
+ cvp_dereg_dev_cfg_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_dereg_dev_cfg_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_dereg_dev_cfg_cmd.hdr.token = 0;
cvp_dereg_dev_cfg_cmd.hdr.opcode =
@@ -1832,7 +1979,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvp_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_reg_cal_cmd) - APR_HDR_SIZE);
- cvp_reg_cal_cmd.hdr.src_port = v->session_id;
+ cvp_reg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_reg_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_reg_cal_cmd.hdr.token = 0;
cvp_reg_cal_cmd.hdr.opcode =
@@ -1897,7 +2045,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvp_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_dereg_cal_cmd) - APR_HDR_SIZE);
- cvp_dereg_cal_cmd.hdr.src_port = v->session_id;
+ cvp_dereg_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_dereg_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_dereg_cal_cmd.hdr.token = 0;
cvp_dereg_cal_cmd.hdr.opcode =
@@ -1961,7 +2110,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvp_reg_vol_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_reg_vol_cal_cmd) - APR_HDR_SIZE);
- cvp_reg_vol_cal_cmd.hdr.src_port = v->session_id;
+ cvp_reg_vol_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_reg_vol_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_reg_vol_cal_cmd.hdr.token = 0;
cvp_reg_vol_cal_cmd.hdr.opcode =
@@ -2030,7 +2180,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvp_dereg_vol_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_dereg_vol_cal_cmd) - APR_HDR_SIZE);
- cvp_dereg_vol_cal_cmd.hdr.src_port = v->session_id;
+ cvp_dereg_vol_cal_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_dereg_vol_cal_cmd.hdr.dest_port = voice_get_cvp_handle(v);
cvp_dereg_vol_cal_cmd.hdr.token = 0;
cvp_dereg_vol_cal_cmd.hdr.opcode =
@@ -2111,7 +2262,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
mvm_map_phys_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_map_phys_cmd) - APR_HDR_SIZE);
- mvm_map_phys_cmd.hdr.src_port = v->session_id;
+ mvm_map_phys_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_map_phys_cmd.hdr.dest_port = voice_get_mvm_handle(v);
mvm_map_phys_cmd.hdr.token = token;
mvm_map_phys_cmd.hdr.opcode = VSS_IMEMORY_CMD_MAP_PHYSICAL;
@@ -2216,7 +2368,8 @@
sizeof(cvp_session_cmd) - APR_HDR_SIZE);
pr_debug(" send create cvp session, pkt size = %d\n",
cvp_session_cmd.hdr.pkt_size);
- cvp_session_cmd.hdr.src_port = v->session_id;
+ cvp_session_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_session_cmd.hdr.dest_port = 0;
cvp_session_cmd.hdr.token = 0;
cvp_session_cmd.hdr.opcode =
@@ -2347,7 +2500,8 @@
sizeof(cvp_enable_cmd) - APR_HDR_SIZE);
pr_debug("cvp_enable_cmd pkt size = %d, cvp_handle=%d\n",
cvp_enable_cmd.pkt_size, cvp_handle);
- cvp_enable_cmd.src_port = v->session_id;
+ cvp_enable_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_enable_cmd.dest_port = cvp_handle;
cvp_enable_cmd.token = 0;
cvp_enable_cmd.opcode = VSS_IVOCPROC_CMD_ENABLE;
@@ -2395,7 +2549,8 @@
APR_PKT_VER);
mvm_set_cal_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_set_cal_network) - APR_HDR_SIZE);
- mvm_set_cal_network.hdr.src_port = v->session_id;
+ mvm_set_cal_network.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_set_cal_network.hdr.dest_port = mvm_handle;
mvm_set_cal_network.hdr.token = 0;
mvm_set_cal_network.hdr.opcode = VSS_IMVM_CMD_SET_CAL_NETWORK;
@@ -2454,7 +2609,8 @@
APR_PKT_VER);
mvm_set_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_set_network) - APR_HDR_SIZE);
- mvm_set_network.hdr.src_port = v->session_id;
+ mvm_set_network.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_set_network.hdr.dest_port = mvm_handle;
mvm_set_network.hdr.token = 0;
mvm_set_network.hdr.opcode = VSS_ICOMMON_CMD_SET_NETWORK;
@@ -2484,7 +2640,8 @@
mvm_set_voice_timing.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mvm_set_voice_timing) -
APR_HDR_SIZE);
- mvm_set_voice_timing.hdr.src_port = v->session_id;
+ mvm_set_voice_timing.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_set_voice_timing.hdr.dest_port = mvm_handle;
mvm_set_voice_timing.hdr.token = 0;
mvm_set_voice_timing.hdr.opcode = VSS_ICOMMON_CMD_SET_VOICE_TIMING;
@@ -2542,7 +2699,8 @@
sizeof(mvm_a_vocproc_cmd) - APR_HDR_SIZE);
pr_debug("send mvm_a_vocproc_cmd pkt size = %d\n",
mvm_a_vocproc_cmd.hdr.pkt_size);
- mvm_a_vocproc_cmd.hdr.src_port = v->session_id;
+ mvm_a_vocproc_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_a_vocproc_cmd.hdr.dest_port = mvm_handle;
mvm_a_vocproc_cmd.hdr.token = 0;
mvm_a_vocproc_cmd.hdr.opcode = VSS_IMVM_CMD_ATTACH_VOCPROC;
@@ -2611,7 +2769,8 @@
sizeof(mvm_d_vocproc_cmd) - APR_HDR_SIZE);
pr_debug("mvm_d_vocproc_cmd pkt size = %d\n",
mvm_d_vocproc_cmd.hdr.pkt_size);
- mvm_d_vocproc_cmd.hdr.src_port = v->session_id;
+ mvm_d_vocproc_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_d_vocproc_cmd.hdr.dest_port = mvm_handle;
mvm_d_vocproc_cmd.hdr.token = 0;
mvm_d_vocproc_cmd.hdr.opcode = VSS_IMVM_CMD_DETACH_VOCPROC;
@@ -2645,7 +2804,8 @@
sizeof(cvp_destroy_session_cmd) - APR_HDR_SIZE);
pr_debug("cvp_destroy_session_cmd pkt size = %d\n",
cvp_destroy_session_cmd.pkt_size);
- cvp_destroy_session_cmd.src_port = v->session_id;
+ cvp_destroy_session_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_destroy_session_cmd.dest_port = cvp_handle;
cvp_destroy_session_cmd.token = 0;
cvp_destroy_session_cmd.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
@@ -2673,7 +2833,7 @@
}
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
- unsigned int bufcnt)
+ uint32_t mem_handle)
{
struct vss_imemory_cmd_unmap_t mem_unmap;
int ret = 0;
@@ -2697,11 +2857,12 @@
APR_PKT_VER);
mem_unmap.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(mem_unmap) - APR_HDR_SIZE);
- mem_unmap.hdr.src_port = v->session_id;
+ mem_unmap.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
mem_unmap.hdr.dest_port = mvm_handle;
mem_unmap.hdr.token = 0;
mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
- mem_unmap.mem_handle = v->shmem_info.mem_handle;
+ mem_unmap.mem_handle = mem_handle;
pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);
@@ -2758,7 +2919,8 @@
packet_exchange_config_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(packet_exchange_config_pkt) -
APR_HDR_SIZE);
- packet_exchange_config_pkt.hdr.src_port = v->session_id;
+ packet_exchange_config_pkt.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
packet_exchange_config_pkt.hdr.dest_port = cvs_handle;
packet_exchange_config_pkt.hdr.token = 0;
packet_exchange_config_pkt.hdr.opcode =
@@ -2818,7 +2980,8 @@
APR_PKT_VER);
data_exchange_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(data_exchange_pkt) - APR_HDR_SIZE);
- data_exchange_pkt.hdr.src_port = v->session_id;
+ data_exchange_pkt.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
data_exchange_pkt.hdr.dest_port = cvs_handle;
data_exchange_pkt.hdr.token = 0;
data_exchange_pkt.hdr.opcode = VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE;
@@ -2865,7 +3028,8 @@
APR_PKT_VER);
cvs_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_mute_cmd) - APR_HDR_SIZE);
- cvs_mute_cmd.hdr.src_port = v->session_id;
+ cvs_mute_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_mute_cmd.hdr.dest_port = voice_get_cvs_handle(v);
cvs_mute_cmd.hdr.token = 0;
cvs_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
@@ -2918,7 +3082,8 @@
APR_PKT_VER);
cvp_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_mute_cmd) - APR_HDR_SIZE);
- cvp_mute_cmd.hdr.src_port = v->session_id;
+ cvp_mute_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
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;
@@ -2972,7 +3137,8 @@
APR_PKT_VER);
cvp_vol_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvp_vol_cmd) - APR_HDR_SIZE);
- cvp_vol_cmd.hdr.src_port = v->session_id;
+ cvp_vol_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvp_vol_cmd.hdr.dest_port = cvp_handle;
cvp_vol_cmd.hdr.token = 0;
cvp_vol_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX;
@@ -3021,7 +3187,8 @@
APR_PKT_VER);
cvs_start_record.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_start_record) - APR_HDR_SIZE);
- cvs_start_record.hdr.src_port = v->session_id;
+ cvs_start_record.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_start_record.hdr.dest_port = cvs_handle;
cvs_start_record.hdr.token = 0;
cvs_start_record.hdr.opcode = VSS_IRECORD_CMD_START;
@@ -3106,7 +3273,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvs_stop_record.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_stop_record) - APR_HDR_SIZE);
- cvs_stop_record.src_port = v->session_id;
+ cvs_stop_record.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_stop_record.dest_port = cvs_handle;
cvs_stop_record.token = 0;
cvs_stop_record.opcode = VSS_IRECORD_CMD_STOP;
@@ -3277,7 +3445,8 @@
APR_PKT_VER);
cvs_start_playback.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_start_playback) - APR_HDR_SIZE);
- cvs_start_playback.hdr.src_port = v->session_id;
+ cvs_start_playback.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_start_playback.hdr.dest_port = cvs_handle;
cvs_start_playback.hdr.token = 0;
cvs_start_playback.hdr.opcode = VSS_IPLAYBACK_CMD_START;
@@ -3341,7 +3510,8 @@
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
cvs_stop_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(cvs_stop_playback) - APR_HDR_SIZE);
- cvs_stop_playback.src_port = v->session_id;
+ cvs_stop_playback.src_port =
+ voice_get_idx_for_session(v->session_id);
cvs_stop_playback.dest_port = cvs_handle;
cvs_stop_playback.token = 0;
@@ -3412,7 +3582,7 @@
return ret;
}
-int voc_disable_cvp(uint16_t session_id)
+int voc_disable_cvp(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3446,7 +3616,7 @@
return ret;
}
-int voc_enable_cvp(uint16_t session_id)
+int voc_enable_cvp(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3521,7 +3691,7 @@
return ret;
}
-static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+static int voice_set_packet_exchange_mode_and_config(uint32_t session_id,
uint32_t mode)
{
struct voice_data *v = voice_get_session(session_id);
@@ -3553,7 +3723,7 @@
return -EINVAL;
}
-int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute)
+int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3578,7 +3748,7 @@
return ret;
}
-int voc_set_rx_device_mute(uint16_t session_id, uint32_t mute)
+int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3603,7 +3773,7 @@
return ret;
}
-int voc_get_rx_device_mute(uint16_t session_id)
+int voc_get_rx_device_mute(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3623,7 +3793,7 @@
return ret;
}
-int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode)
+int voc_set_tty_mode(uint32_t session_id, uint8_t tty_mode)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3643,7 +3813,7 @@
return ret;
}
-uint8_t voc_get_tty_mode(uint16_t session_id)
+uint8_t voc_get_tty_mode(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3663,7 +3833,7 @@
return ret;
}
-int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable)
+int voc_set_pp_enable(uint32_t session_id, uint32_t module_id, uint32_t enable)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3690,7 +3860,7 @@
return ret;
}
-int voc_get_pp_enable(uint16_t session_id, uint32_t module_id)
+int voc_get_pp_enable(uint32_t session_id, uint32_t module_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3709,7 +3879,7 @@
return ret;
}
-int voc_set_rx_vol_index(uint16_t session_id, uint32_t dir, uint32_t vol_idx)
+int voc_set_rx_vol_index(uint32_t session_id, uint32_t dir, uint32_t vol_idx)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3734,7 +3904,7 @@
return ret;
}
-int voc_set_rxtx_port(uint16_t session_id, uint32_t port_id, uint32_t dev_type)
+int voc_set_rxtx_port(uint32_t session_id, uint32_t port_id, uint32_t dev_type)
{
struct voice_data *v = voice_get_session(session_id);
@@ -3758,7 +3928,7 @@
return 0;
}
-int voc_set_route_flag(uint16_t session_id, uint8_t path_dir, uint8_t set)
+int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set)
{
struct voice_data *v = voice_get_session(session_id);
@@ -3782,7 +3952,7 @@
return 0;
}
-uint8_t voc_get_route_flag(uint16_t session_id, uint8_t path_dir)
+uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3805,7 +3975,7 @@
return ret;
}
-int voc_end_voice_call(uint16_t session_id)
+int voc_end_voice_call(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3834,7 +4004,7 @@
return ret;
}
-int voc_standby_voice_call(uint16_t session_id)
+int voc_standby_voice_call(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
struct apr_hdr mvm_standby_voice_cmd;
@@ -3863,7 +4033,8 @@
sizeof(mvm_standby_voice_cmd) - APR_HDR_SIZE);
pr_debug("send mvm_standby_voice_cmd pkt size = %d\n",
mvm_standby_voice_cmd.pkt_size);
- mvm_standby_voice_cmd.src_port = v->session_id;
+ mvm_standby_voice_cmd.src_port =
+ voice_get_idx_for_session(v->session_id);
mvm_standby_voice_cmd.dest_port = mvm_handle;
mvm_standby_voice_cmd.token = 0;
mvm_standby_voice_cmd.opcode = VSS_IMVM_CMD_STANDBY_VOICE;
@@ -3881,7 +4052,7 @@
return ret;
}
-int voc_set_lch(uint16_t session_id, enum voice_lch_mode lch_mode)
+int voc_set_lch(uint32_t session_id, enum voice_lch_mode lch_mode)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3924,7 +4095,7 @@
return ret;
}
-int voc_resume_voice_call(uint16_t session_id)
+int voc_resume_voice_call(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3940,7 +4111,7 @@
return -EINVAL;
}
-int voc_start_voice_call(uint16_t session_id)
+int voc_start_voice_call(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -4061,7 +4232,7 @@
struct common_data *c = NULL;
struct voice_data *v = NULL;
int i = 0;
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
if ((data == NULL) || (priv == NULL)) {
pr_err("%s: data or priv is NULL\n", __func__);
@@ -4107,7 +4278,7 @@
pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
- v = voice_get_session(data->dest_port);
+ v = voice_get_session_by_idx(data->dest_port);
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
@@ -4199,7 +4370,7 @@
struct common_data *c = NULL;
struct voice_data *v = NULL;
int i = 0;
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
if ((data == NULL) || (priv == NULL)) {
pr_err("%s: data or priv is NULL\n", __func__);
@@ -4244,7 +4415,7 @@
return 0;
}
- v = voice_get_session(data->dest_port);
+ v = voice_get_session_by_idx(data->dest_port);
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
@@ -4346,7 +4517,8 @@
APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(send_enc_buf_consumed_cmd) - APR_HDR_SIZE);
- send_enc_buf_consumed_cmd.hdr.src_port = v->session_id;
+ send_enc_buf_consumed_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
send_enc_buf_consumed_cmd.hdr.dest_port = cvs_handle;
send_enc_buf_consumed_cmd.hdr.token = 0;
send_enc_buf_consumed_cmd.hdr.opcode =
@@ -4392,7 +4564,8 @@
send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
sizeof(send_dec_buf) - APR_HDR_SIZE);
- send_dec_buf.hdr.src_port = v->session_id;
+ send_dec_buf.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
send_dec_buf.hdr.dest_port = cvs_handle;
send_dec_buf.hdr.token = 0;
send_dec_buf.hdr.opcode =
@@ -4473,7 +4646,7 @@
struct common_data *c = NULL;
struct voice_data *v = NULL;
int i = 0;
- uint16_t session_id = 0;
+ uint32_t session_id = 0;
if ((data == NULL) || (priv == NULL)) {
pr_err("%s: data or priv is NULL\n", __func__);
@@ -4514,7 +4687,7 @@
return 0;
}
- v = voice_get_session(data->dest_port);
+ v = voice_get_session_by_idx(data->dest_port);
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
@@ -4727,8 +4900,10 @@
mutex_init(&common.common_lock);
+ /* Initialize session id with vsid */
+ init_session_id();
+
for (i = 0; i < MAX_VOC_SESSIONS; i++) {
- common.voice[i].session_id = SESSION_ID_BASE + i;
/* initialize dev_rx and dev_tx */
common.voice[i].dev_rx.volume = common.default_vol_val;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 386634b..5a16115 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1258,7 +1258,7 @@
struct voice_dev_route_state voc_route_state;
- u16 session_id;
+ u32 session_id;
struct incall_rec_info rec_info;
@@ -1274,7 +1274,6 @@
};
#define MAX_VOC_SESSIONS 4
-#define SESSION_ID_BASE 0xFFF0
struct common_data {
/* these default values are for all devices */
@@ -1337,34 +1336,39 @@
#define VOLTE_SESSION_NAME "VoLTE session"
#define VOICE2_SESSION_NAME "Voice2 session"
-#define VOICE2_SESSION_VSID "10DC1000"
+#define VOICE2_SESSION_VSID_STR "10DC1000"
+#define VOICE_SESSION_VSID 0x10C01000
+#define VOICE2_SESSION_VSID 0x10DC1000
+#define VOLTE_SESSION_VSID 0x10C02000
+#define VOIP_SESSION_VSID 0x10004000
+#define ALL_SESSION_VSID 0xFFFFFFFF
/* called by alsa driver */
-int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
+int voc_set_pp_enable(uint32_t session_id, uint32_t module_id,
uint32_t enable);
-int voc_get_pp_enable(uint16_t session_id, uint32_t module_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,
+int voc_get_pp_enable(uint32_t session_id, uint32_t module_id);
+uint8_t voc_get_tty_mode(uint32_t session_id);
+int voc_set_tty_mode(uint32_t session_id, uint8_t tty_mode);
+int voc_start_voice_call(uint32_t session_id);
+int voc_end_voice_call(uint32_t session_id);
+int voc_standby_voice_call(uint32_t session_id);
+int voc_resume_voice_call(uint32_t session_id);
+int voc_set_lch(uint32_t session_id, enum voice_lch_mode lch_mode);
+int voc_set_rxtx_port(uint32_t session_id,
uint32_t dev_port_id,
uint32_t dev_type);
-int voc_set_rx_vol_index(uint16_t session_id, uint32_t dir, uint32_t voc_idx);
-int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute);
-int voc_set_rx_device_mute(uint16_t session_id, uint32_t mute);
-int voc_get_rx_device_mute(uint16_t session_id);
-int voc_disable_cvp(uint16_t session_id);
-int voc_enable_cvp(uint16_t session_id);
-int voc_set_route_flag(uint16_t session_id, uint8_t path_dir, uint8_t set);
-uint8_t voc_get_route_flag(uint16_t session_id, uint8_t path_dir);
-int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable);
+int voc_set_rx_vol_index(uint32_t session_id, uint32_t dir, uint32_t voc_idx);
+int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute);
+int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute);
+int voc_get_rx_device_mute(uint32_t session_id);
+int voc_disable_cvp(uint32_t session_id);
+int voc_enable_cvp(uint32_t session_id);
+int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set);
+uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
+int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
void voc_disable_dtmf_det_on_active_sessions(void);
-uint16_t voc_get_session_id(char *name);
+uint32_t voc_get_session_id(char *name);
int voc_start_playback(uint32_t set);
int voc_start_record(uint32_t port_id, uint32_t set);