Merge "usb: otg: Add device tree parameter lpm-on-dev-suspend"
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
new file mode 100644
index 0000000..0d56b34
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -0,0 +1,15 @@
+Qualcomm IMEM
+
+IMEM is fast on-chip memory used for various debug features and dma transactions.
+
+Required properties
+
+-compatible: "qcom,msm-imem"
+-reg: start address and size of imem memory
+
+Example:
+
+ qcom,msm-imem {
+ compatible = "qcom,msm-imem";
+ reg = <0xdeadbeef 0x1000>; /* < start_address size > */
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 4129f7f..b359c49 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -8,6 +8,10 @@
lpm-level. The units for voltage are dependent on the PMIC used on the target
and are in uV.
+The optional properties are:
+
+- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
+
The required nodes for lpm-levels are:
- compatible: "qcom,lpm-levels"
@@ -34,6 +38,7 @@
Example:
qcom,lpm-levels {
+ qcom,use-qtimer;
qcom,lpm-level@0 {
reg = <0>;
qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index f860618..9635972 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -32,6 +32,9 @@
- coresight-child-ports : list of input port numbers of the children
- coresight-default-sink : represents the default compile time CoreSight sink
- qcom,pc-save : program counter save implemented
+- qcom,blk-size : block size for tmc-etr to usb transfers
+- qcom,round-robin : indicates if per core etms are allowed round-robin access
+ by the funnel
Examples:
@@ -105,4 +108,5 @@
coresight-child-list = <&funnel_kpss>;
coresight-child-ports = <0>;
qcom,pc-save;
+ qcom,round-robin;
};
diff --git a/Documentation/devicetree/bindings/input/gen_vkeys.txt b/Documentation/devicetree/bindings/input/gen_vkeys.txt
new file mode 100644
index 0000000..da99e19
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gen_vkeys.txt
@@ -0,0 +1,24 @@
+Touchscreen Virtual Keys Device
+
+Generate virtual keys sysfs entry for Android
+
+Required properties:
+
+ - compatible : should be "qcom,gen-vkeys"
+ - label : name of the touch controller
+ - qcom,disp-maxx : Maximum x-coordinate of display
+ - qcom,disp-maxy : Maximum y-coordinate of display
+ - qcom,panel-maxx : Maximum x-coordinate of touch panel
+ - qcom,panel-maxy : Maximum y-coordinate of touch panel
+ - qcom,key-codes : Array of key codes for virtual keys
+
+Example:
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <720>;
+ qcom,disp-maxy = <1280>;
+ qcom,panel-maxx = <760>;
+ qcom,panel-maxy = <1424>;
+ qcom,key-codes = <158 139 102 217>;
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
index bcea355..dde1a16 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -22,6 +22,8 @@
- atmel,fw-name : firmware name to used for flashing firmware
Optional property:
+ - atmel,bl-addr : bootloader address, by default is looked up
+ in mxt_slave_addresses structure
- atmel,config : configuration parameter for the controller
- atmel,i2c-pull-up : specify to indicate pull up is needed
- vcc_i2c-supply : Power source required to pull up i2c bus
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index da0708f..b9bac1d 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -61,6 +61,7 @@
Optional properties for RGB led:
- 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".
Example:
@@ -96,7 +97,8 @@
qcom,duty-pcts = [00 19 32 4B 64
64 4B 32 19 00];
qcom,max-current = <12>;
- qcom,default-state = "off";
+ qcom,default-state = "on";
+ qcom,turn-off-delay-ms = <500>;
qcom,id = <5>;
linux,default-trigger = "none";
};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 2f2ea22..6af445b 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -3,6 +3,11 @@
Required properties:
- compatible : one of:
- "qcom,msm-vidc"
+- hfi : supported Host-Firmware Interface, one of:
+ - "venus"
+ - "q6"
+
+Optional properties:
- reg : offset and length of the register set for the device.
- interrupts : should contain the vidc interrupt.
- vidc-cp-map : start and size of device virtual address range for secure buffers.
@@ -13,9 +18,6 @@
or non-secure.
- load-freq-tbl : load (in macroblocks/sec) and corresponding vcodec clock
required for optimal performance in descending order.
-- hfi : supported Host-Firmware Interface, one of:
- - "venus"
- - "q6"
Example:
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 5bef9b8..22e43ab 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -20,6 +20,8 @@
images and self-authentication is not desired;
<1> if the hardware requires self-authenticating images.
- qcom,is-loadable: if PIL is required to load the modem image
+- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
Example:
qcom,mss@fc880000 {
@@ -38,4 +40,10 @@
qcom,is-loadable;
qcom,firmware-name = "mba";
qcom,pil-self-auth = <1>;
+
+ /* GPIO inputs from mss */
+ gpio_err_fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+
+ /* GPIO output to mss */
+ gpio_force_stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
};
diff --git a/Documentation/devicetree/bindings/power/bq28400-battery.txt b/Documentation/devicetree/bindings/power/bq28400-battery.txt
index 1460d70..a95e61f 100644
--- a/Documentation/devicetree/bindings/power/bq28400-battery.txt
+++ b/Documentation/devicetree/bindings/power/bq28400-battery.txt
@@ -4,15 +4,20 @@
The device interface is I2C, its I2C slave 7-bit address is 0xb.
The device is usually embedded inside the "smart battery" pack.
-node required properties:
-- compatible: Must be "ti,bq28400-battery" or "ti,bq30z55-battery"
-- reg: I2C Address must be 0xb.
+Required properties:
+
+ - compatible : Must be "ti,bq28400-battery" or "ti,bq30z55-battery"
+ - reg : I2C Address must be 0xb.
+ - ti,temp-cold : Cold temperature limit in celsius degree
+ - ti,temp-hot : Hot temperature limit in celsius degree
Example:
i2c@f9967000 {
battery@b {
compatible = "ti,bq28400-battery", "ti,bq30z55-battery";
reg = <0xb>;
+ ti,temp-cold = <2>;
+ ti,temp-hot = <43>;
};
};
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index fddae80..149445d 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -2,13 +2,25 @@
Required properties:
- compatible: Must be "qcom,krait-regulator"
-- reg: Specifies the address and size for this regulator device
+- reg: Specifies the address and size for this regulator device,
+ also specifies the address and the size for the MDD area
+ to be used along with the regulator
+- reg-names: "acs" -string to identify the area where main power control
+ registers reside.
+ "mdd" - string to identify the area where mdd registers reside.
- qcom,headroom-voltage: The minimum required voltage drop between the input
voltage and the output voltage for the LDO to be
- operational, in microvolts
-- qcom,retention-voltage: The value for retention voltage in microvolts
-- qcom,ldo-default-voltage: The default value for LDO voltage in microvolts
-- qcom,ldo-threshold-voltage: The voltage value above which LDO is nonfunctional
+ operational, in microvolts. Acceptable values are from
+ 50000uV to 250000uV
+- qcom,retention-voltage: The value for retention voltage in microvolts. Acceptable
+ values are from 465000uV to 750000uV
+- qcom,ldo-default-voltage: The default value for LDO voltage in microvolts. Acceptable
+ values are from 465000uV to 750000uV
+- qcom,ldo-threshold-voltage: The voltage value above which LDO is nonfunctional.
+ Acceptable values are from 600000uV to 900000uV
+- qcom,ldo-delta-voltage: The delta used to reduce the requested voltage in order
+ to derive the LDO output voltage while switching
+ to LDO mode. Acceptable values are from 1000uV to 100000uV
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
@@ -17,11 +29,15 @@
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
regulator-name = "krait0";
- reg = <0xf9088000 0x1000>;
+ reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+ <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+ reg-names = "acs", "mdd";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1100000>;
qcom,headroom-voltage = <150000>;
qcom,retention-voltage = <745000>;
qcom,ldo-default-voltage = <745000>;
qcom,ldo-threshold-voltage = <750000>;
+ qcom,ldo-delta-voltage = <50000>;
};
+
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3d022a3..975d51c 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -54,6 +54,23 @@
- compatible : "qcom,msm-pcm-afe"
+* msm-pcm-dtmf
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dtmf"
+ - qcom,msm-pcm-dtmf : Enable DTMF driver in Audio. DTMF driver is
+ used for generation and detection of DTMF tones, when user is in
+ active voice call. APR commands are sent from DTMF driver to ADSP.
+
+* msm-dai-stub
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-stub"
+ - qcom,msm-dai-stub : This enables stub CPU dai in Audio.
+ The stub dai is used when there is no real backend in Audio.
+
* msm-dai-q6-hdmi
Required properties:
@@ -85,9 +102,11 @@
- qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
Value is from 16384 to 16393
BT SCO port ID value from 12288 to 12289
- RT Proxy port ID values from 224 to 225 and 240 to 241
+ RT Proxy port ID values from 224 to 225 and 240 to
+ 241
FM Rx and TX port ID values from 12292 to 12293
- incall record Rx and TX port ID values from 32771 to 32772
+ incall record Rx and TX port ID values from 32771 to
+ 32772
* msm-auxpcm
@@ -161,22 +180,24 @@
- qcom,msm_bus,num_cases: Total number of use cases
- - qcom,msm_bus,active_only: Context flag for requests in active or
- dual (active & sleep) contex
+ - qcom,msm_bus,active_only: Context flag for requests in active
+ or dual (active & sleep) contex
- qcom,msm_bus,num_paths: Total number of master-slave pairs
- - qcom,msm_bus,vectors: Arrays of unsigned integers representing:
- master-id, slave-id, arbitrated bandwidth,
- instantaneous bandwidth
+ - qcom,msm_bus,vectors: Arrays of unsigned integers
+ representing:
+ master-id, slave-id, arbitrated
+ bandwidth,
+ instantaneous bandwidth
* wcd9xxx_intc
Required properties:
- compatible : "qcom,wcd9xxx-irq"
- - interrupt-controller : Mark this device node as an interrupt
- controller
+ - interrupt-controller : Mark this device node as an
+ interrupt controller
- #interrupt-cells : Should be 1
@@ -218,6 +239,14 @@
compatible = "qcom,msm-dai-fe";
};
+ qcom,msm-pcm-dtmf {
+ compatible = "qcom,msm-pcm-dtmf";
+ };
+
+ qcom,msm-dai-stub {
+ compatible = "qcom,msm-dai-stub";
+ };
+
qcom,msm-dai-q6-hdmi {
compatible = "qcom,msm-dai-q6-hdmi";
qcom,msm-dai-q6-dev-id = <8>;
@@ -442,25 +471,34 @@
Required properties:
- compatible : "qcom,msm-dai-q6-mi2s"
- - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to transfer data
- to (WCD9XXX) codec. If slimbus interface is used then
- "msm-dai-q6" needs to be filled with correct data for slimbus
- interface. The sections "msm-dai-mi2s" is used by MDM or MSM
- to use I2S interface with codec. This section is used by CPU
- driver in ASOC MSM to configure MI2S interface. MSM internally
- has multiple MI2S namely Primary, Secondary, Tertiary and
- Quaternary MI2S. They are represented with id 0, 1, 2, 3
- respectively. The field "qcom,msm-dai-q6-mi2s-dev-id" represents
- which of the MI2S block is used. These MI2S are connected to I2S
- interface.
+ - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to
+ transfer data to (WCD9XXX) codec.
+ If slimbus interface is used then "msm-dai-q6"
+ needs to be filled with correct data for
+ slimbus interface.
+ The sections "msm-dai-mi2s" is used by MDM or
+ MSM to use I2S interface with codec.
+ This section is used by CPU driver in ASOC MSM
+ to configure MI2S interface. MSM internally
+ has multiple MI2S namely Primary, Secondary,
+ Tertiary and Quaternary MI2S.
+ They are represented with id 0, 1, 2, 3
+ respectively.
+ The field "qcom,msm-dai-q6-mi2s-dev-id"
+ represents which of the MI2S block is used.
+ These MI2S are connected to I2S interface.
- - qcom,msm-mi2s-rx-lines: Each MI2S interface in MSM has one or more SD lines. These lines
- are used for data transfer between codec and MSM. This element in
- indicates which output RX lines are used in the MI2S interface.
+ - qcom,msm-mi2s-rx-lines: Each MI2S interface in MSM has one or more SD
+ lines. These lines are used for data transfer
+ between codec and MSM.
+ This element in indicates which output RX lines
+ are used in the MI2S interface.
- - qcom,msm-mi2s-tx-lines: Each MI2S interface in MSM has one or more SD lines. These lines
- are used for data transfer between codec and MSM. This element in
- indicates which input TX lines are used in the MI2S interface.
+ - qcom,msm-mi2s-tx-lines: Each MI2S interface in MSM has one or more SD
+ lines. These lines are used for data transfer
+ between codec and MSM.
+ This element in indicates which input TX lines
+ are used in the MI2S interface.
Example:
@@ -540,9 +578,9 @@
It is possible that some MSM use PIL to load the ADSP image. While
other MSM may use SBL to load the ADSP image at boot. Audio APR needs
state of ADSP to register and enable APR to be used for sending commands
- to ADSP. so adsp-state represents the state of ADSP to ADSP loader. Value
- of 0 indicates ADSP loader needs to use PIL and value of 2 means ADSP
- image is already loaded by SBL.
+ to ADSP. so adsp-state represents the state of ADSP to ADSP loader.
+ Value of 0 indicates ADSP loader needs to use PIL and value of 2 means
+ ADSP image is already loaded by SBL.
Example:
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 74c25a0..989bea8 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -8,33 +8,39 @@
- qcom,cdc-reset-gpio: gpio used for codec SOC reset.
- <supply-name>-supply: phandle to the regulator device tree node
- - qcom,<supply-name>-voltage - specifies voltage levels for supply. Should be
- specified in pairs (min, max), units mV.
+ - qcom,<supply-name>-voltage - specifies voltage levels for supply.
+ Should be specified in pairs (min, max), units mV.
- qcom,<supply-name>-current - specifies max current in mA that can drawn
- from the <supply-name>.
+ from the <supply-name>.
- above three properties with "supply-name" set to "qcom,cdc-vdd-buck", "qcom,cdc-vdd-tx-h",
- "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1", "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1",
- "qcom,cdc-vddcx-2" should be present.
+ above three properties with "supply-name" set to "qcom,cdc-vdd-buck",
+ "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
+ "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
+ should be present.
- - qcom,cdc-micbias-ldoh-v - LDOH output in volts ( should be 1.95 V and 3.00 V).
+ - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
- qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
- qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
- qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
- - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
- - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
- - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
- - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1
+ (should be from 1 to 3).
+ - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2
+ (should be from 1 to 3).
+ - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3
+ (should be from 1 to 3).
+ - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4
+ (should be from 1 to 3).
This value represents the connected CFLIT to MIC Bias.
- qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
- qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
- qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
- qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
- - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for
+ codec.
- qcom,cdc-slim-ifd-dev - namme of the codec slim interface device.
- qcom,cdc-slim-ifd-elemental-addr - codec slimbus slave interface device
enumeration address.
@@ -97,33 +103,39 @@
- reg: represents the slave address provided to the I2C driver.
- qcom,cdc-reset-gpio: gpio used for codec SOC reset.
- <supply-name>-supply: phandle to the regulator device tree node.
- - qcom,<supply-name>-voltage - specifies voltage levels for supply. Should be
- specified in pairs (min, max), units mV.
+ - qcom,<supply-name>-voltage - specifies voltage levels for supply.
+ Should be specified in pairs (min, max), units mV.
- qcom,<supply-name>-current - specifies max current in mA that can drawn
- from the <supply-name>.
+ from the <supply-name>.
- above three properties with "supply-name" set to "qcom,cdc-vdd-buck", "qcom,cdc-vdd-tx-h",
- "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1", "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1",
- "qcom,cdc-vddcx-2" should be present.
+ above three properties with "supply-name" set to "qcom,cdc-vdd-buck",
+ "qcom,cdc-vdd-tx-h", "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1",
+ "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1", "qcom,cdc-vddcx-2"
+ should be present.
- - qcom,cdc-micbias-ldoh-v - LDOH output in volts ( should be 1.95 V and 3.00 V).
+ - qcom,cdc-micbias-ldoh-v - LDOH output in volts (should be 1.95 V and 3.00 V).
- qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
- qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
- qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
- - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
- - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
- - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
- - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1
+ (should be from 1 to 3).
+ - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2
+ (should be from 1 to 3).
+ - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3
+ (should be from 1 to 3).
+ - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4
+ (should be from 1 to 3).
This value represents the connected CFLIT to MIC Bias.
- qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
- qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
- qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
- qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
- - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for
+ codec.
Example:
i2c@f9925000 {
@@ -143,7 +155,8 @@
reg = <0x0d>;
qcom,cdc-reset-gpio = <&msmgpio 22 0>;
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>;
cdc-vdd-buck-supply = <&pm8019_l11>;
qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
index 3534823..91c2461 100644
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
@@ -3,11 +3,19 @@
Required properties:
- compatible :
- "qcom,msm-hsuart-v14" to be used for UARTDM Core v1.4
+- cell-index : cell-index to be used as device id to enumerate
+ TTY based HSUART device as /dev/ttyHS<cell-index>.
+ Device probe fails if cell-index is not available.
+ The cell-index value should be from 0 to 255.
- reg : offset and length of the register set for both the device,
uart core and bam core
-- reg-names : names of the uart core and bam core.
-- interrupts : should contain the uart interrupt.
-- interrupt-names : names of interrupts to be used.
+- reg-names :
+ - "core_mem" to be used as name of the uart core
+ - "bam_mem" to be used as name of the bam core
+- interrupts : interrupts for both the device,uart core and bam core
+- interrupt-names :
+ - "core_irq" to be used as uart irq
+ - "bam irq" to be used as bam irq
- bam-tx-ep-pipe-index : BAM TX Endpoint Pipe Index for HSUART
- bam-rx-ep-pipe-index : BAM RX Endpoint Pipe Index for HSUART
@@ -28,6 +36,7 @@
uart7@f995d000 {
compatible = "qcom,msm-hsuart-v14";
+ cell-index = <0>;
reg = <0xf995d000 0x1000>,
<0xf9944000 0x5000>;
reg-names = "core_mem", "bam_mem";
@@ -54,6 +63,7 @@
uart7: uart@f995d000 {
compatible = "qcom,msm-hsuart-v14"
+ cell-index = <0>;
reg = <0x19c40000 0x1000">,
<0xf9944000 0x5000>;
reg-names = "core_mem", "bam_mem";
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 23d1505..2616e90 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -78,6 +78,34 @@
<87 512 60000000 960000000>;
};
+MSM HSUSB EHCI controller
+
+Required properties :
+- compatible : should be "qcom,ehci-host"
+- reg : offset and length of the register set in the memory map
+- interrupts: IRQ lines used by this controller
+- interrupt-names : Required interrupt resource entries are:
+ HSUSB EHCI expects "core_irq" and optionally "async_irq".
+- <supply-name>-supply: handle to the regulator device tree node
+ Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+- qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
+
+Optional properties :
+- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+
+Example MSM HSUSB EHCI controller device node :
+ ehci: qcom,ehci-host@f9a55000 {
+ compatible = "qcom,ehci-host";
+ reg = <0xf9a55000 0x400>;
+ interrupts = <0 134 0>, <0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSUSB_VDDCX-supply = <&pm8841_s2>;
+ HSUSB_1p8-supply = <&pm8941_l6>;
+ HSUSB_3p3-supply = <&pm8941_l24>;
+ qcom,usb2-enable-hsphy2;
+ qcom,usb2-power-budget = <500>;
+ };
+
ANDROID USB:
Required properties:
@@ -157,6 +185,8 @@
Optional properties :
- qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
while performing PIPE RESET
+- qcom,disable-clk-gating: If present then disable BAM clock gating.
+
Example USB BAM controller device node:
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5a9cecf..2f686fa 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2049,7 +2049,7 @@
Provide support for Coprocessor register access using /sys
interface. Read and write to CP registers from userspace
through sysfs interface. A sys file (cp_rw) will be created under
- /sys/devices/system/cpaccess/cpaccess0.
+ /sys/devices/cpaccess/cpaccess0.
If unsure, say N.
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
index 5a9e1ee..9bb642d 100755
--- a/arch/arm/boot/dts/msm-iommu.dtsi
+++ b/arch/arm/boot/dts/msm-iommu.dtsi
@@ -40,8 +40,8 @@
0x2010
0x2014>;
- qcom,iommu-bfb-data = <0xffffffff
- 0xffffffff
+ qcom,iommu-bfb-data = <0x0000ffff
+ 0x0
0x4
0x4
0x0
@@ -111,7 +111,7 @@
0x2020>;
qcom,iommu-bfb-data = <0xffffffff
- 0xffffffff
+ 0x0
0x00000004
0x00000010
0x00000000
@@ -261,8 +261,8 @@
0x2414
0x2008>;
- qcom,iommu-bfb-data = <0xffffffff
- 0xffffffff
+ qcom,iommu-bfb-data = <0x00000003
+ 0x0
0x00000004
0x00000010
0x00000000
@@ -322,7 +322,7 @@
0x2020>;
qcom,iommu-bfb-data = <0xffffffff
- 0xffffffff
+ 0x00000000
0x4
0x8
0x0
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
new file mode 100644
index 0000000..e107b36
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -0,0 +1,402 @@
+/* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ qcom,spm@f9089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9089000 0x1000>;
+ qcom,core-id = <0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-pmic-data0 = <0x02030080>;
+ qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
+ qcom,pfm-port = <0x2>;
+ qcom,saw2-spm-cmd-ret = [0b 00 03 00 7b 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 6b c0 e0 d0 42 07
+ 78 1f 80 4e d0 e0 c0 22 6b 50 4b 60 02 32 50 7b
+ 0f];
+ qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 0b 10 e0 d0 6b c0
+ 42 f0 11 07 01 b0 78 1f 80 4e c0 d0 12 e0 6b 50 4b
+ 60 02 32 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ };
+
+ qcom,lpm-resources {
+ compatible = "qcom,lpm-resources";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-resources@0 {
+ reg = <0x0>;
+ qcom,name = "vdd-dig";
+ qcom,resource-type = <0>;
+ qcom,type = <0x62706d73>; /* "smpb" */
+ qcom,id = <0x02>;
+ qcom,key = <0x6e726f63>; /* "corn" */
+ qcom,init-value = <5>; /* Super Turbo */
+ };
+
+ qcom,lpm-resources@1 {
+ reg = <0x1>;
+ qcom,name = "vdd-mem";
+ qcom,resource-type = <0>;
+ qcom,type = <0x62706d73>; /* "smpb" */
+ qcom,id = <0x01>;
+ qcom,key = <0x7675>; /* "uv" */
+ qcom,init-value = <1050000>; /* Super Turbo */
+ };
+
+ qcom,lpm-resources@2 {
+ reg = <0x2>;
+ qcom,name = "pxo";
+ qcom,resource-type = <0>;
+ qcom,type = <0x306b6c63>; /* "clk0" */
+ qcom,id = <0x00>;
+ qcom,key = <0x62616e45>; /* "Enab" */
+ qcom,init-value = <1>; /* On */
+ };
+
+ qcom,lpm-resources@3 {
+ reg = <0x3>;
+ qcom,name = "l2";
+ qcom,resource-type = <1>;
+ qcom,init-value = <2>; /* Retention */
+ };
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-level@0 {
+ reg = <0x0>;
+ qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <1>;
+ qcom,ss-power = <784>;
+ qcom,energy-overhead = <190000>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,lpm-level@1 {
+ reg = <0x1>;
+ qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <75>;
+ qcom,ss-power = <735>;
+ qcom,energy-overhead = <77341>;
+ qcom,time-overhead = <105>;
+ };
+
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
+ qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <95>;
+ qcom,ss-power = <725>;
+ qcom,energy-overhead = <99500>;
+ qcom,time-overhead = <130>;
+ };
+
+ qcom,lpm-level@3 {
+ reg = <0x3>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <138>;
+ qcom,energy-overhead = <1208400>;
+ qcom,time-overhead = <3200>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <2>; /* RETENTION HIGH */
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <110>;
+ qcom,energy-overhead = <1250300>;
+ qcom,time-overhead = <3500>;
+ };
+
+ qcom,lpm-level@5 {
+ reg = <0x5>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <68>;
+ qcom,energy-overhead = <1350200>;
+ qcom,time-overhead = <4000>;
+ };
+
+ qcom,lpm-level@6 {
+ reg = <0x6>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <10300>;
+ qcom,ss-power = <63>;
+ qcom,energy-overhead = <2128000>;
+ qcom,time-overhead = <18200>;
+ };
+
+ qcom,lpm-level@7 {
+ reg = <0x7>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <2>; /* RETIONTION HIGH */
+ qcom,latency-us = <18000>;
+ qcom,ss-power = <10>;
+ qcom,energy-overhead = <3202600>;
+ qcom,time-overhead = <27000>;
+ };
+
+ qcom,lpm-level@8 {
+ reg = <0x8>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
+ qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
+ qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <2>;
+ qcom,energy-overhead = <4252000>;
+ qcom,time-overhead = <32000>;
+ };
+ };
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ };
+
+ qcom,mpm@fc4281d0 {
+ compatible = "qcom,mpm-v2";
+ reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+ <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ interrupts = <0 171 1>;
+
+ qcom,ipc-bit-offset = <1>;
+
+ qcom,gic-parent = <&intc>;
+ qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ <53 104>, /* mdss_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 57>, /* mss_to_apps_irq(0) */
+ <0xff 58>, /* mss_to_apps_irq(1) */
+ <0xff 59>, /* mss_to_apps_irq(2) */
+ <0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_low */
+ <0xff 176>, /* o_wcss_apss_smsm_irq */
+ <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+ <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+ <0xff 179>, /* o_wcss_apss_asic_intr
+
+ <0xff 188>, /* lpass_irq_out_apcs(0) */
+ <0xff 189>, /* lpass_irq_out_apcs(1) */
+ <0xff 190>, /* lpass_irq_out_apcs(2) */
+ <0xff 191>, /* lpass_irq_out_apcs(3) */
+ <0xff 192>, /* lpass_irq_out_apcs(4) */
+ <0xff 193>, /* lpass_irq_out_apcs(5) */
+ <0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* lpass_irq_out_apcs(7) */
+ <0xff 196>, /* lpass_irq_out_apcs(8) */
+ <0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 200>, /* rpm_ipc(4) */
+ <0xff 201>, /* rpm_ipc(5) */
+ <0xff 202>, /* rpm_ipc(6) */
+ <0xff 203>, /* rpm_ipc(7) */
+ <0xff 204>, /* rpm_ipc(24) */
+ <0xff 205>, /* rpm_ipc(25) */
+ <0xff 206>, /* rpm_ipc(26) */
+ <0xff 207>, /* rpm_ipc(27) */
+ <0xff 240>; /* summary_irq_kpss */
+
+ qcom,gpio-parent = <&msmgpio>;
+ qcom,gpio-map = <3 102>,
+ <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>,
+ <38 92>,
+ <39 93>,
+ <40 95>;
+ };
+
+ qcom,pc-cntr@fe805664 {
+ compatible = "qcom,pc-cntr";
+ reg = <0xfe805664 0x40>;
+ };
+
+ qcom,pm-8x60 {
+ compatible = "qcom,pm-8x60";
+ qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,use-sync-timer;
+ };
+
+ qcom,rpm-stats@0xfc19dbd0{
+ compatible = "qcom,rpm-stats";
+ reg = <0xfc19dbd0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 854a708..e8c25a8 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -14,6 +14,7 @@
/include/ "msm8226-ion.dtsi"
/include/ "msm-gdsc.dtsi"
/include/ "msm8226-iommu.dtsi"
+/include/ "msm8226-pm.dtsi"
/ {
model = "Qualcomm MSM 8226";
@@ -60,6 +61,11 @@
status = "disabled";
};
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+
qcom,sps@f9984000 {
compatible = "qcom,msm_sps";
reg = <0xf9984000 0x15000>,
@@ -70,11 +76,11 @@
usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
- interrupts = <0 134 0>;
- interrupt-names = "core_irq";
- HSUSB_VDDCX-supply = <&pm8026_s1>;
- HSUSB_1p8-supply = <&pm8026_l10>;
- HSUSB_3p3-supply = <&pm8026_l20>;
+ interrupts = <0 134 0>, <0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSUSB_VDDCX-supply = <&pm8026_s1>;
+ HSUSB_1p8-supply = <&pm8026_l10>;
+ HSUSB_3p3-supply = <&pm8026_l20>;
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
@@ -388,6 +394,13 @@
};
};
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ rpm-standalone;
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
new file mode 100644
index 0000000..e107b36
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -0,0 +1,402 @@
+/* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ qcom,spm@f9089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9089000 0x1000>;
+ qcom,core-id = <0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
+ 5b 80 10 2b 30 06 26 30 0f];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-pmic-data0 = <0x02030080>;
+ qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
+ qcom,pfm-port = <0x2>;
+ qcom,saw2-spm-cmd-ret = [0b 00 03 00 7b 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 6b c0 e0 d0 42 07
+ 78 1f 80 4e d0 e0 c0 22 6b 50 4b 60 02 32 50 7b
+ 0f];
+ qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 0b 10 e0 d0 6b c0
+ 42 f0 11 07 01 b0 78 1f 80 4e c0 d0 12 e0 6b 50 4b
+ 60 02 32 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ };
+
+ qcom,lpm-resources {
+ compatible = "qcom,lpm-resources";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-resources@0 {
+ reg = <0x0>;
+ qcom,name = "vdd-dig";
+ qcom,resource-type = <0>;
+ qcom,type = <0x62706d73>; /* "smpb" */
+ qcom,id = <0x02>;
+ qcom,key = <0x6e726f63>; /* "corn" */
+ qcom,init-value = <5>; /* Super Turbo */
+ };
+
+ qcom,lpm-resources@1 {
+ reg = <0x1>;
+ qcom,name = "vdd-mem";
+ qcom,resource-type = <0>;
+ qcom,type = <0x62706d73>; /* "smpb" */
+ qcom,id = <0x01>;
+ qcom,key = <0x7675>; /* "uv" */
+ qcom,init-value = <1050000>; /* Super Turbo */
+ };
+
+ qcom,lpm-resources@2 {
+ reg = <0x2>;
+ qcom,name = "pxo";
+ qcom,resource-type = <0>;
+ qcom,type = <0x306b6c63>; /* "clk0" */
+ qcom,id = <0x00>;
+ qcom,key = <0x62616e45>; /* "Enab" */
+ qcom,init-value = <1>; /* On */
+ };
+
+ qcom,lpm-resources@3 {
+ reg = <0x3>;
+ qcom,name = "l2";
+ qcom,resource-type = <1>;
+ qcom,init-value = <2>; /* Retention */
+ };
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-level@0 {
+ reg = <0x0>;
+ qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <1>;
+ qcom,ss-power = <784>;
+ qcom,energy-overhead = <190000>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,lpm-level@1 {
+ reg = <0x1>;
+ qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <75>;
+ qcom,ss-power = <735>;
+ qcom,energy-overhead = <77341>;
+ qcom,time-overhead = <105>;
+ };
+
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
+ qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <95>;
+ qcom,ss-power = <725>;
+ qcom,energy-overhead = <99500>;
+ qcom,time-overhead = <130>;
+ };
+
+ qcom,lpm-level@3 {
+ reg = <0x3>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <138>;
+ qcom,energy-overhead = <1208400>;
+ qcom,time-overhead = <3200>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <2>; /* RETENTION HIGH */
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <110>;
+ qcom,energy-overhead = <1250300>;
+ qcom,time-overhead = <3500>;
+ };
+
+ qcom,lpm-level@5 {
+ reg = <0x5>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <68>;
+ qcom,energy-overhead = <1350200>;
+ qcom,time-overhead = <4000>;
+ };
+
+ qcom,lpm-level@6 {
+ reg = <0x6>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <10300>;
+ qcom,ss-power = <63>;
+ qcom,energy-overhead = <2128000>;
+ qcom,time-overhead = <18200>;
+ };
+
+ qcom,lpm-level@7 {
+ reg = <0x7>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <2>; /* RETIONTION HIGH */
+ qcom,latency-us = <18000>;
+ qcom,ss-power = <10>;
+ qcom,energy-overhead = <3202600>;
+ qcom,time-overhead = <27000>;
+ };
+
+ qcom,lpm-level@8 {
+ reg = <0x8>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
+ qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
+ qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <2>;
+ qcom,energy-overhead = <4252000>;
+ qcom,time-overhead = <32000>;
+ };
+ };
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ };
+
+ qcom,mpm@fc4281d0 {
+ compatible = "qcom,mpm-v2";
+ reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+ <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ interrupts = <0 171 1>;
+
+ qcom,ipc-bit-offset = <1>;
+
+ qcom,gic-parent = <&intc>;
+ qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ <53 104>, /* mdss_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 57>, /* mss_to_apps_irq(0) */
+ <0xff 58>, /* mss_to_apps_irq(1) */
+ <0xff 59>, /* mss_to_apps_irq(2) */
+ <0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_low */
+ <0xff 176>, /* o_wcss_apss_smsm_irq */
+ <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+ <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+ <0xff 179>, /* o_wcss_apss_asic_intr
+
+ <0xff 188>, /* lpass_irq_out_apcs(0) */
+ <0xff 189>, /* lpass_irq_out_apcs(1) */
+ <0xff 190>, /* lpass_irq_out_apcs(2) */
+ <0xff 191>, /* lpass_irq_out_apcs(3) */
+ <0xff 192>, /* lpass_irq_out_apcs(4) */
+ <0xff 193>, /* lpass_irq_out_apcs(5) */
+ <0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* lpass_irq_out_apcs(7) */
+ <0xff 196>, /* lpass_irq_out_apcs(8) */
+ <0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 200>, /* rpm_ipc(4) */
+ <0xff 201>, /* rpm_ipc(5) */
+ <0xff 202>, /* rpm_ipc(6) */
+ <0xff 203>, /* rpm_ipc(7) */
+ <0xff 204>, /* rpm_ipc(24) */
+ <0xff 205>, /* rpm_ipc(25) */
+ <0xff 206>, /* rpm_ipc(26) */
+ <0xff 207>, /* rpm_ipc(27) */
+ <0xff 240>; /* summary_irq_kpss */
+
+ qcom,gpio-parent = <&msmgpio>;
+ qcom,gpio-map = <3 102>,
+ <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>,
+ <38 92>,
+ <39 93>,
+ <40 95>;
+ };
+
+ qcom,pc-cntr@fe805664 {
+ compatible = "qcom,pc-cntr";
+ reg = <0xfe805664 0x40>;
+ };
+
+ qcom,pm-8x60 {
+ compatible = "qcom,pm-8x60";
+ qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,use-sync-timer;
+ };
+
+ qcom,rpm-stats@0xfc19dbd0{
+ compatible = "qcom,rpm-stats";
+ reg = <0xfc19dbd0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 4d00d2b..d013cba 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -14,6 +14,7 @@
/include/ "msm-iommu-v1.dtsi"
/include/ "msm8610-ion.dtsi"
/include/ "msm-gdsc.dtsi"
+/include/ "msm8610-pm.dtsi"
/ {
model = "Qualcomm MSM 8610";
@@ -46,6 +47,16 @@
clock-frequency = <19200000>;
};
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -53,6 +64,11 @@
status = "disabled";
};
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ hfi = "q6";
+ };
+
usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
@@ -210,6 +226,13 @@
};
};
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ rpm-standalone;
+ };
+
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
@@ -308,6 +331,15 @@
<0x155000cf>; /* LDO_22 */
};
+ qcom,lpass@fe200000 {
+ compatible = "qcom,pil-q6v5-lpass";
+ reg = <0xfe200000 0x00100>,
+ <0xfd485100 0x00010>;
+ reg-names = "qdsp6_base", "halt_base";
+ interrupts = <0 162 1>;
+
+ qcom,firmware-name = "adsp";
+ };
};
&gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 3b3402d..06bab30 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -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
@@ -265,6 +265,15 @@
wp-gpios = <&pm8941_gpios 29 0x1>;
};
+&uart7 {
+ status = "ok";
+};
+
+&ehci {
+ status = "ok";
+ vbus-supply = <&usb2_otg_sw>;
+};
+
&usb3 {
qcom,otg-capability;
};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index ee3df10..6bb7b28 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -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
@@ -190,5 +190,7 @@
coresight-id = <14>;
coresight-name = "coresight-csr";
coresight-nr-inports = <0>;
+
+ qcom,blk-size = <3>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index d8e15b8..2e18dfa 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -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
@@ -195,6 +195,12 @@
};
};
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
+
&spmi_bus {
qcom,pm8941@1 {
qcom,leds@d800 {
@@ -279,8 +285,6 @@
&pm8941_chg {
status = "ok";
- qcom,chg-charging-disabled;
-
qcom,chg-chgr@1000 {
status = "ok";
};
@@ -362,7 +366,7 @@
qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
- qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
qcom,master-en = <1>;
};
@@ -501,9 +505,9 @@
mpp@a700 { /* MPP 8 */
qcom,mode = <1>; /* DIG_OUT */
qcom,output-type = <0>; /* CMOS */
- qcom,pull-up = <0>;
+ qcom,pull = <0>;
qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
+ qcom,src-sel = <0>; /* CONSTANT */
qcom,master-en = <1>; /* ENABLE MPP */
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 7368788..f0f79b0 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -26,6 +26,8 @@
battery@b {
compatible = "ti,bq28400-battery";
reg = <0xb>;
+ ti,temp-cold = <2>; /* degree celsius */
+ ti,temp-hot = <43>; /* degree celsius */
};
charger@2b {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index c295353..40eaf2d 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -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
@@ -257,6 +257,10 @@
qcom,hsusb-otg-otg-control = <2>;
};
+&uart7 {
+ status = "ok";
+};
+
&usb3 {
qcom,otg-capability;
};
@@ -268,8 +272,6 @@
&pm8941_chg {
status = "ok";
- qcom,chg-charging-disabled;
-
qcom,chg-chgr@1000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
index 1302ccb..ab105a9 100644
--- a/arch/arm/boot/dts/msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-pm.dtsi
@@ -179,6 +179,8 @@
#address-cells = <1>;
#size-cells = <0>;
+ qcom,use-qtimer;
+
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 9b8e506..c6c5452 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -426,49 +426,61 @@
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
regulator-name = "krait0";
- reg = <0xf9088000 0x1000>;
+ reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+ <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+ reg-names = "acs", "mdd";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1100000>;
qcom,headroom-voltage = <150000>;
- qcom,retention-voltage = <745000>;
- qcom,ldo-default-voltage = <745000>;
- qcom,ldo-threshold-voltage = <750000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
};
krait1_vreg: regulator@f9098000 {
compatible = "qcom,krait-regulator";
regulator-name = "krait1";
- reg = <0xf9098000 0x1000>;
+ reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */
+ <0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */
+ reg-names = "acs", "mdd";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1100000>;
qcom,headroom-voltage = <150000>;
- qcom,retention-voltage = <745000>;
- qcom,ldo-default-voltage = <745000>;
- qcom,ldo-threshold-voltage = <750000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
};
krait2_vreg: regulator@f90a8000 {
compatible = "qcom,krait-regulator";
regulator-name = "krait2";
- reg = <0xf90a8000 0x1000>;
+ reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */
+ <0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */
+ reg-names = "acs", "mdd";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1100000>;
qcom,headroom-voltage = <150000>;
- qcom,retention-voltage = <745000>;
- qcom,ldo-default-voltage = <745000>;
- qcom,ldo-threshold-voltage = <750000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
};
krait3_vreg: regulator@f90b8000 {
compatible = "qcom,krait-regulator";
regulator-name = "krait3";
- reg = <0xf90b8000 0x1000>;
+ reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */
+ <0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */
+ reg-names = "acs", "mdd";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1100000>;
qcom,headroom-voltage = <150000>;
- qcom,retention-voltage = <745000>;
- qcom,ldo-default-voltage = <745000>;
- qcom,ldo-threshold-voltage = <750000>;
+ qcom,retention-voltage = <675000>;
+ qcom,ldo-default-voltage = <750000>;
+ qcom,ldo-threshold-voltage = <850000>;
+ qcom,ldo-delta-voltage = <50000>;
};
spi_eth_vreg: spi_eth_phy_vreg {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 4919391..38e552e 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -75,7 +75,7 @@
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
+ qcom,i2c-src-freq = <19200000>;
gpios = <&msmgpio 83 0>, /* DAT */
<&msmgpio 84 0>; /* CLK */
};
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
new file mode 100644
index 0000000..60f63a8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -0,0 +1,194 @@
+/* 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.
+ */
+/ {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ qcom,smp2p-wcnss {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ /* SMP2P Test Driver for inbound entries */
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for outbound entries */
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ /* SMP2P Test Driver for modem inbound */
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for modem output */
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ /* SMP2P SSR Driver for inbound entry from modem. */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* SMP2P SSR Driver for outbound entry to modem */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* SMP2P Test Driver for adsp inbound */
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for adsp output */
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ /* SMP2P Test Driver for wcnss inbound */
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for wcnss output */
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-cdp.dts
rename to arch/arm/boot/dts/msm8974-v1-cdp.dts
index b8b3141..15ff424 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
/include/ "msm8974-cdp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-fluid.dts
rename to arch/arm/boot/dts/msm8974-v1-fluid.dts
index b014e14..0b435a3 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -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
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
/include/ "msm8974-fluid.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-v1-liquid.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-liquid.dts
rename to arch/arm/boot/dts/msm8974-v1-liquid.dts
index ef38036..5c12569 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-liquid.dts
@@ -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
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
/include/ "msm8974-liquid.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-mtp.dts
rename to arch/arm/boot/dts/msm8974-v1-mtp.dts
index 9946cf0..01e9fe2 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -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
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
/include/ "msm8974-mtp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-v1-rumi.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-rumi.dts
rename to arch/arm/boot/dts/msm8974-v1-rumi.dts
index 738ff86..ebb37b7 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-v1-rumi.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
/include/ "msm8974-rumi.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-v1-sim.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8974-sim.dts
rename to arch/arm/boot/dts/msm8974-v1-sim.dts
index 09ea419..29add5d 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-v1-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -12,7 +12,7 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v1.dtsi"
/include/ "msm8974-sim.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
new file mode 100644
index 0000000..e60ab28
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -0,0 +1,26 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974.dtsi"
+
+/ {
+ qcom,msm-imem@fc42b000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfc42b000 0x1000>; /* Address and size of IMEM */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-v2-cdp.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-cdp.dts
copy to arch/arm/boot/dts/msm8974-v2-cdp.dts
index b8b3141..58e172f 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
/include/ "msm8974-cdp.dtsi"
/ {
- model = "Qualcomm MSM 8974 CDP";
+ model = "Qualcomm MSM 8974v2 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974";
- qcom,msm-id = <126 1 0>;
+ qcom,msm-id = <126 1 0x20000>;
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-v2-fluid.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-fluid.dts
copy to arch/arm/boot/dts/msm8974-v2-fluid.dts
index b014e14..5759b56 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-fluid.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
/include/ "msm8974-fluid.dtsi"
/ {
- model = "Qualcomm MSM 8974 FLUID";
+ model = "Qualcomm MSM 8974v2 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974";
- qcom,msm-id = <126 3 0>;
+ qcom,msm-id = <126 3 0x20000>;
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-v2-liquid.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-liquid.dts
copy to arch/arm/boot/dts/msm8974-v2-liquid.dts
index ef38036..6812f60 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-liquid.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
/include/ "msm8974-liquid.dtsi"
/ {
- model = "Qualcomm MSM 8974 LIQUID";
+ model = "Qualcomm MSM 8974v2 LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974";
- qcom,msm-id = <126 9 0>;
+ qcom,msm-id = <126 9 0x20000>;
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
similarity index 77%
copy from arch/arm/boot/dts/msm8974-mtp.dts
copy to arch/arm/boot/dts/msm8974-v2-mtp.dts
index 9946cf0..b29d4ca 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-/include/ "msm8974.dtsi"
+/include/ "msm8974-v2.dtsi"
/include/ "msm8974-mtp.dtsi"
/ {
- model = "Qualcomm MSM 8974 MTP";
+ model = "Qualcomm MSM 8974v2 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974";
- qcom,msm-id = <126 8 0>;
+ qcom,msm-id = <126 8 0x20000>;
};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
new file mode 100644
index 0000000..3ddf4da9
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -0,0 +1,26 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974.dtsi"
+
+/ {
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c7505cb..7960e41 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -19,6 +19,7 @@
/include/ "msm8974-ion.dtsi"
/include/ "msm8974-gpu.dtsi"
/include/ "msm8974-mdss.dtsi"
+/include/ "msm8974-smp2p.dtsi"
/ {
model = "Qualcomm MSM 8974";
@@ -340,6 +341,46 @@
cs-gpios = <&msmgpio 55 0>;
};
+ tspp: msm_tspp@f99d8000 {
+ compatible = "qcom,msm_tspp";
+ cell-index = <0>;
+ reg = <0xf99d8000 0x1000>, /* MSM_TSIF0_PHYS */
+ <0xf99d9000 0x1000>, /* MSM_TSIF1_PHYS */
+ <0xf99da000 0x1000>, /* MSM_TSPP_PHYS */
+ <0xf99c4000 0x14000>; /* MSM_TSPP_BAM_PHYS */
+ reg-names = "MSM_TSIF0_PHYS",
+ "MSM_TSIF1_PHYS",
+ "MSM_TSPP_PHYS",
+ "MSM_TSPP_BAM_PHYS";
+ interrupts = <0 153 0>, /* TSIF_TSPP_IRQ */
+ <0 151 0>, /* TSIF0_IRQ */
+ <0 152 0>, /* TSIF1_IRQ */
+ <0 154 0>; /* TSIF_BAM_IRQ */
+ interrupt-names = "TSIF_TSPP_IRQ",
+ "TSIF0_IRQ",
+ "TSIF1_IRQ",
+ "TSIF_BAM_IRQ";
+ qcom,tsif-pclk = "iface_clk";
+ qcom,tsif-ref-clk = "ref_clk";
+ gpios = <&msmgpio 89 0>, /* TSIF0 CLK */
+ <&msmgpio 90 0>, /* TSIF0 EN */
+ <&msmgpio 91 0>, /* TSIF0 DATA */
+ <&msmgpio 92 0>, /* TSIF0 SYNC */
+ <&msmgpio 93 0>, /* TSIF1 CLK */
+ <&msmgpio 94 0>, /* TSIF1 EN */
+ <&msmgpio 95 0>, /* TSIF1 DATA */
+ <&msmgpio 96 0>; /* TSIF1 SYNC */
+ qcom,gpio-names = "tsif_clk",
+ "tsif_en",
+ "tsif_data",
+ "tsif_sync",
+ "tsif_clk",
+ "tsif_en",
+ "tsif_data",
+ "tsif_sync";
+ qcom,gpios-func = <1>;
+ };
+
slim_msm: slim@fe12f000 {
cell-index = <1>;
compatible = "qcom,slim-ngd";
@@ -595,7 +636,7 @@
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
+ qcom,i2c-src-freq = <19200000>;
};
i2c@f9924000 {
@@ -608,7 +649,7 @@
interrupts = <0 96 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
+ qcom,i2c-src-freq = <19200000>;
};
spi@f9923000 {
@@ -671,6 +712,19 @@
<61 512 240000 960000>;
};
+ ehci: qcom,ehci-host@f9a55000 {
+ compatible = "qcom,ehci-host";
+ status = "disabled";
+ reg = <0xf9a55000 0x400>;
+ interrupts = <0 134 0>, <0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSUSB_VDDCX-supply = <&pm8841_s2>;
+ HSUSB_1p8-supply = <&pm8941_l6>;
+ HSUSB_3p3-supply = <&pm8941_l24>;
+ qcom,usb2-enable-hsphy2;
+ qcom,usb2-power-budget = <500>;
+ };
+
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
parent-supply = <&pm8841_s4_corner>;
};
@@ -896,6 +950,12 @@
qcom,is-loadable;
qcom,firmware-name = "mba";
qcom,pil-self-auth = <1>;
+
+ /* GPIO input from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
};
qcom,pronto@fb21b000 {
@@ -1095,6 +1155,7 @@
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
qcom,pipe1 {
label = "usb-to-peri-qdss-dwc3";
@@ -1178,6 +1239,20 @@
qcom,memblock-remove = <0x7f00000 0x8000000>; /* Address and Size of Hole */
};
+ uart7: uart@f995d000 { /*BLSP #2, UART #7 */
+ cell-index = <0>;
+ compatible = "qcom,msm-hsuart-v14";
+ status = "disabled";
+ reg = <0xf995d000 0x1000>,
+ <0xf9944000 0x5000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupts = <0 113 0>, <0 239 0>;
+ interrupt-names = "core_irq", "bam_irq";
+
+ qcom,bam-tx-ep-pipe-index = <0>;
+ qcom,bam-rx-ep-pipe-index = <1>;
+ };
+
qcom,smem@fa00000 {
compatible = "qcom,smem";
reg = <0xfa00000 0x200000>,
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 9a49c32..7a5aa5c 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -117,6 +117,8 @@
coresight-outports = <0>;
coresight-child-list = <&funnel_in0>;
coresight-child-ports = <4>;
+
+ qcom,round-robin;
};
csr: csr@fc302000 {
@@ -126,5 +128,7 @@
coresight-id = <9>;
coresight-name = "coresight-csr";
coresight-nr-inports = <0>;
+
+ qcom,blk-size = <1>;
};
};
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 71fcfd6..5a925cb 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -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
@@ -71,6 +71,8 @@
#address-cells = <1>;
#size-cells = <0>;
+ qcom,use-qtimer;
+
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
diff --git a/arch/arm/boot/dts/msm9625-smp2p.dtsi b/arch/arm/boot/dts/msm9625-smp2p.dtsi
new file mode 100644
index 0000000..425bf00
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-smp2p.dtsi
@@ -0,0 +1,152 @@
+/* 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.
+ */
+/ {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ /* SMP2P Test Driver for inbound entries */
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for outbound entries */
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ /* SMP2P Test Driver for modem inbound */
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for modem output */
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ /* SMP2P SSR Driver for inbound entry from modem. */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* SMP2P SSR Driver for outbound entry to modem */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* SMP2P Test Driver for adsp inbound */
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for adsp output */
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-v1-cdp.dts
similarity index 91%
rename from arch/arm/boot/dts/msm9625-cdp.dts
rename to arch/arm/boot/dts/msm9625-v1-cdp.dts
index f2a798a..6221ba1 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v1-cdp.dts
@@ -12,12 +12,14 @@
/dts-v1/;
-/include/ "msm9625.dtsi"
+/include/ "msm9625-v1.dtsi"
/ {
- model = "Qualcomm MSM 9625 CDP";
+ model = "Qualcomm MSM 9625V1 CDP";
compatible = "qcom,msm9625-cdp", "qcom,msm9625";
- qcom,msm-id = <134 1 0>, <152 1 0>, <149 1 0>, <150 1 0>;
+ qcom,msm-id = <134 1 0>, <152 1 0>, <149 1 0>, <150 1 0>,
+ <151 1 0>, <148 1 0>, <173 1 0>, <174 1 0>,
+ <175 1 0>;
i2c@f9925000 {
charger@57 {
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-v1-mtp.dts
similarity index 91%
rename from arch/arm/boot/dts/msm9625-mtp.dts
rename to arch/arm/boot/dts/msm9625-v1-mtp.dts
index 584fc7f..5ff9e92 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v1-mtp.dts
@@ -12,12 +12,14 @@
/dts-v1/;
-/include/ "msm9625.dtsi"
+/include/ "msm9625-v1.dtsi"
/ {
- model = "Qualcomm MSM 9625 MTP";
+ model = "Qualcomm MSM 9625V1 MTP";
compatible = "qcom,msm9625-mtp", "qcom,msm9625";
- qcom,msm-id = <134 7 0>, <152 7 0>, <149 7 0>, <150 7 0>;
+ qcom,msm-id = <134 7 0>, <152 7 0>, <149 7 0>, <150 7 0>,
+ <151 7 0>, <148 7 0>, <173 7 0>, <174 7 0>,
+ <175 7 0>;
i2c@f9925000 {
charger@57 {
diff --git a/arch/arm/boot/dts/msm9625-rumi.dts b/arch/arm/boot/dts/msm9625-v1-rumi.dts
similarity index 83%
rename from arch/arm/boot/dts/msm9625-rumi.dts
rename to arch/arm/boot/dts/msm9625-v1-rumi.dts
index dadb3f7..a854947 100644
--- a/arch/arm/boot/dts/msm9625-rumi.dts
+++ b/arch/arm/boot/dts/msm9625-v1-rumi.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -12,10 +12,10 @@
/dts-v1/;
-/include/ "msm9625.dtsi"
+/include/ "msm9625-v1.dtsi"
/ {
- model = "Qualcomm MSM 9625 RUMI";
+ model = "Qualcomm MSM 9625V1 RUMI";
compatible = "qcom,msm9625-rumi", "qcom,msm9625";
qcom,msm-id = <134 15 0>;
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
new file mode 100644
index 0000000..8dc93cb
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -0,0 +1,26 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+ qcom,msm-imem@fc42b000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfc42b000 0x1000>; /* Address and size of IMEM */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
similarity index 86%
copy from arch/arm/boot/dts/msm9625-cdp.dts
copy to arch/arm/boot/dts/msm9625-v2-cdp.dts
index f2a798a..244556d 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, 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
@@ -12,12 +12,14 @@
/dts-v1/;
-/include/ "msm9625.dtsi"
+/include/ "msm9625-v2.dtsi"
/ {
- model = "Qualcomm MSM 9625 CDP";
+ model = "Qualcomm MSM 9625V2 CDP";
compatible = "qcom,msm9625-cdp", "qcom,msm9625";
- qcom,msm-id = <134 1 0>, <152 1 0>, <149 1 0>, <150 1 0>;
+ qcom,msm-id = <134 1 0x20000>, <152 1 0x20000>, <149 1 0x20000>,
+ <150 1 0x20000>, <151 1 0x20000>, <148 1 0x20000>,
+ <173 1 0x20000>, <174 1 0x20000>, <175 1 0x20000>;
i2c@f9925000 {
charger@57 {
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
similarity index 86%
copy from arch/arm/boot/dts/msm9625-mtp.dts
copy to arch/arm/boot/dts/msm9625-v2-mtp.dts
index 584fc7f..bf0f539 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, 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
@@ -12,12 +12,14 @@
/dts-v1/;
-/include/ "msm9625.dtsi"
+/include/ "msm9625-v2.dtsi"
/ {
- model = "Qualcomm MSM 9625 MTP";
+ model = "Qualcomm MSM 9625V2 MTP";
compatible = "qcom,msm9625-mtp", "qcom,msm9625";
- qcom,msm-id = <134 7 0>, <152 7 0>, <149 7 0>, <150 7 0>;
+ qcom,msm-id = <134 7 0x20000>, <152 7 0x20000>, <149 7 0x20000>,
+ <150 7 0x20000>, <151 7 0x20000>, <148 7 0x20000>,
+ <173 7 0x20000>, <174 7 0x20000>, <175 7 0x20000>;
i2c@f9925000 {
charger@57 {
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
new file mode 100644
index 0000000..3695e71
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -0,0 +1,26 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d374b59..7d3f7e9 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -14,6 +14,7 @@
/include/ "msm9625-ion.dtsi"
/include/ "msm9625-pm.dtsi"
/include/ "msm9625-coresight.dtsi"
+/include/ "msm9625-smp2p.dtsi"
/ {
model = "Qualcomm MSM 9625";
@@ -111,6 +112,7 @@
qcom,usb-total-bam-num = <3>;
qcom,usb-bam-num-pipes = <16>;
qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
qcom,pipe0 {
label = "usb-to-ipa";
@@ -121,7 +123,6 @@
qcom,data-fifo-size = <0x600>;
qcom,descriptor-fifo-size = <0x300>;
};
-
qcom,pipe1 {
label = "ipa-to-usb";
qcom,usb-bam-type = <1>;
@@ -131,6 +132,32 @@
qcom,data-fifo-size = <0x600>;
qcom,descriptor-fifo-size = <0x100>;
};
+ qcom,pipe2 {
+ label = "usb-to-qdss-hsusb";
+ qcom,usb-bam-type = <1>;
+ qcom,usb-bam-mem-type = <0>;
+ qcom,src-bam-physical-address = <0xf9a44000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0xfc37c000>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0>;
+ qcom,data-fifo-size = <0>;
+ qcom,descriptor-fifo-offset = <0>;
+ qcom,descriptor-fifo-size = <0>;
+ };
+ qcom,pipe3 {
+ label = "qdss-to-usb-hsusb";
+ qcom,usb-bam-type = <1>;
+ qcom,usb-bam-mem-type = <0>;
+ qcom,src-bam-physical-address = <0xfc37c000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0xf9a44000>;
+ qcom,dst-bam-pipe-index = <2>;
+ qcom,data-fifo-offset = <0x4100>;
+ qcom,data-fifo-size = <0x400>;
+ qcom,descriptor-fifo-offset = <0x4000>;
+ qcom,descriptor-fifo-size = <0x400>;
+ };
};
qcom,nand@f9ac0000 {
@@ -502,6 +529,10 @@
compatible = "qcom,msm-pcm-voice";
};
+ qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
qcom,msm-dai-fe {
compatible = "qcom,msm-dai-fe";
};
@@ -514,6 +545,40 @@
compatible = "qcom,msm-pcm-hostless";
};
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+ };
+ qcom,msm-pcm-dtmf {
+ compatible = "qcom,msm-pcm-dtmf";
+ };
+
+ qcom,msm-dai-stub {
+ compatible = "qcom,msm-dai-stub";
+ };
+
+ qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
qcom,msm-dai-mi2s {
compatible = "qcom,msm-dai-mi2s";
qcom,msm-dai-q6-mi2s-prim {
@@ -531,6 +596,12 @@
qcom,mss {
compatible = "qcom,pil-q6v5-mss";
interrupts = <0 24 1>;
+
+ /* GPIO input from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
};
qcom,smem@fa00000 {
@@ -608,6 +679,12 @@
<0xfc330000 0x1000>;
reg-names = "etm-base","debug-base";
};
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x1000>; /* 4K EBI1 buffer */
+ };
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index 85cd09f..3572e5a 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -260,14 +260,10 @@
/*
* cp_register_write_sysfs - sysfs interface for writing to
* CP register
- * @dev: sys device
- * @attr: device attribute
- * @buf: write value
- * @cnt: not used
- *
*/
-static ssize_t cp_register_write_sysfs(struct sys_device *dev,
- struct sysdev_attribute *attr, const char *buf, size_t cnt)
+static ssize_t cp_register_write_sysfs(
+ struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t cnt)
{
char *str_tmp = (char *)buf;
@@ -280,18 +276,24 @@
}
/*
+ * wrapper for deprecated sysdev write interface
+ */
+static ssize_t sysdev_cp_register_write_sysfs(struct sys_device *dev,
+ struct sysdev_attribute *attr, const char *buf, size_t cnt)
+{
+ return cp_register_write_sysfs(NULL, NULL, buf, cnt);
+}
+
+/*
* cp_register_read_sysfs - sysfs interface for reading CP registers
- * @dev: sys device
- * @attr: device attribute
- * @buf: write value
*
* Code to read in the CPxx crn, crm, op1, op2 variables, or into
* the base MRC opcode, store to executable memory, clean/invalidate
* caches and then execute the new instruction and provide the
* result to the caller.
*/
-static ssize_t cp_register_read_sysfs(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
+static ssize_t cp_register_read_sysfs(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int ret;
@@ -310,20 +312,52 @@
}
/*
+ * wrapper for deprecated sysdev read interface
+ */
+static ssize_t sysdev_cp_register_read_sysfs(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ return cp_register_read_sysfs(NULL, NULL, buf);
+}
+
+/*
* Setup sysfs files
*/
-SYSDEV_ATTR(cp_rw, 0644, cp_register_read_sysfs, cp_register_write_sysfs);
+SYSDEV_ATTR(cp_rw, 0644, sysdev_cp_register_read_sysfs,
+ sysdev_cp_register_write_sysfs);
static struct sys_device device_cpaccess = {
.id = 0,
.cls = &cpaccess_sysclass,
};
+static struct device cpaccess_dev = {
+ .init_name = "cpaccess",
+};
+
+static struct kobj_attribute cp_rw_attribute =
+ __ATTR(cp_rw, 0644, cp_register_read_sysfs, cp_register_write_sysfs);
+
+static struct attribute *attrs[] = {
+ &cp_rw_attribute.attr,
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .name = "cpaccess0",
+ .attrs = attrs,
+};
+
/*
* init_cpaccess_sysfs - initialize sys devices
*/
static int __init init_cpaccess_sysfs(void)
{
+ /*
+ * sysdev interface is deprecated and will be removed
+ * after migration to new sysfs entry
+ */
+
int error = sysdev_class_register(&cpaccess_sysclass);
if (!error)
@@ -336,12 +370,28 @@
&attr_cp_rw);
else {
pr_err("Error initializing cpaccess interface\n");
- sysdev_unregister(&device_cpaccess);
- sysdev_class_unregister(&cpaccess_sysclass);
+ goto exit0;
+ }
+
+ error = device_register(&cpaccess_dev);
+ if (error) {
+ pr_err("Error registering cpaccess device\n");
+ goto exit0;
+ }
+ error = sysfs_create_group(&cpaccess_dev.kobj, &attr_group);
+ if (error) {
+ pr_err("Error creating cpaccess sysfs group\n");
+ goto exit1;
}
sema_init(&cp_sem, 1);
+ return 0;
+exit1:
+ device_unregister(&cpaccess_dev);
+exit0:
+ sysdev_unregister(&device_cpaccess);
+ sysdev_class_unregister(&cpaccess_sysclass);
return error;
}
@@ -350,6 +400,9 @@
sysdev_remove_file(&device_cpaccess, &attr_cp_rw);
sysdev_unregister(&device_cpaccess);
sysdev_class_unregister(&cpaccess_sysclass);
+
+ sysfs_remove_group(&cpaccess_dev.kobj, &attr_group);
+ device_unregister(&cpaccess_dev);
}
module_init(init_cpaccess_sysfs);
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 04b18d7..6793a65 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -47,6 +47,9 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_QMI_INTERFACE=y
# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_ADSP_LOADER=m
@@ -179,3 +182,9 @@
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 53c97ce..5f7cc53 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -50,6 +50,7 @@
CONFIG_MACH_MSM8627_CDP=y
CONFIG_MACH_MSM8627_MTP=y
CONFIG_MACH_APQ8064_CDP=y
+CONFIG_MACH_FSM8064_EP=y
CONFIG_MACH_APQ8064_MTP=y
CONFIG_MACH_APQ8064_LIQUID=y
CONFIG_MACH_MPQ8064_CDP=y
@@ -339,6 +340,7 @@
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_MSM_GPIO=y
CONFIG_MEDIA_SUPPORT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 2d97769..73ad361 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -49,6 +49,7 @@
CONFIG_MACH_MSM8627_CDP=y
CONFIG_MACH_MSM8627_MTP=y
CONFIG_MACH_APQ8064_CDP=y
+CONFIG_MACH_FSM8064_EP=y
CONFIG_MACH_APQ8064_MTP=y
CONFIG_MACH_APQ8064_LIQUID=y
CONFIG_MACH_MPQ8064_CDP=y
@@ -344,6 +345,7 @@
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_MSM_GPIO=y
CONFIG_MEDIA_SUPPORT=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a5a9620..76a13f9 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -45,6 +45,8 @@
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
@@ -76,6 +78,7 @@
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -260,6 +263,7 @@
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
@@ -337,9 +341,11 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index ef61e66..aa2d236 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -44,6 +44,8 @@
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
@@ -80,6 +82,7 @@
CONFIG_MSM_CACHE_DUMP=y
CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -227,6 +230,7 @@
CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
+CONFIG_TSPP=m
CONFIG_HAPTIC_ISA1200=y
CONFIG_QSEECOM=y
CONFIG_USB_HSIC_SMSC_HUB=y
@@ -264,6 +268,7 @@
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
@@ -304,6 +309,7 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_DVB_CORE=m
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
@@ -321,6 +327,8 @@
CONFIG_MSM_WFD=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
@@ -340,9 +348,11 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index fda9074..6ec70e1 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -40,6 +40,8 @@
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
@@ -217,6 +219,9 @@
CONFIG_USB_GADGET=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
@@ -302,3 +307,4 @@
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MSM_RTB=y
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 5188dbf..d1a3e61 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -151,6 +151,9 @@
struct hw_perf_event *hwc,
int idx);
+extern void enable_irq_callback(void *);
+extern void disable_irq_callback(void *);
+
#endif /* CONFIG_HW_PERF_EVENTS */
#endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d2e2e44..85b1bb3 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -739,6 +739,36 @@
armpmu->type = ARM_PMU_DEVICE_CPU;
}
+static int cpu_has_active_perf(void)
+{
+ struct pmu_hw_events *hw_events;
+ int enabled;
+
+ if (!cpu_pmu)
+ return 0;
+
+ hw_events = cpu_pmu->get_hw_events();
+ enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events);
+
+ if (enabled)
+ /*Even one event's existence is good enough.*/
+ return 1;
+
+ return 0;
+}
+
+void enable_irq_callback(void *info)
+{
+ int irq = *(unsigned int *)info;
+ enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+void disable_irq_callback(void *info)
+{
+ int irq = *(unsigned int *)info;
+ disable_percpu_irq(irq);
+}
+
/*
* PMU hardware loses all context when a CPU goes offline.
* When a CPU is hotplugged back in, since some hardware registers are
@@ -748,12 +778,50 @@
static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
unsigned long action, void *hcpu)
{
+ int irq;
+
+ if (cpu_has_active_perf()) {
+ switch ((action & ~CPU_TASKS_FROZEN)) {
+
+ case CPU_DOWN_PREPARE:
+ /*
+ * If this is on a multicore CPU, we need
+ * to disarm the PMU IRQ before disappearing.
+ */
+ if (cpu_pmu &&
+ cpu_pmu->plat_device->dev.platform_data) {
+ irq = platform_get_irq(cpu_pmu->plat_device, 1);
+ smp_call_function_single((int)hcpu,
+ disable_irq_callback, &irq, 1);
+ }
+ return NOTIFY_DONE;
+
+ case CPU_UP_PREPARE:
+ /*
+ * If this is on a multicore CPU, we need
+ * to arm the PMU IRQ before appearing.
+ */
+ if (cpu_pmu &&
+ cpu_pmu->plat_device->dev.platform_data) {
+ irq = platform_get_irq(cpu_pmu->plat_device, 1);
+ smp_call_function_single((int)hcpu,
+ enable_irq_callback, &irq, 1);
+ }
+ return NOTIFY_DONE;
+
+ case CPU_STARTING:
+ if (cpu_pmu && cpu_pmu->reset) {
+ cpu_pmu->reset(NULL);
+ return NOTIFY_OK;
+ }
+ default:
+ return NOTIFY_DONE;
+ }
+ }
+
if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
return NOTIFY_DONE;
- if (cpu_pmu && cpu_pmu->reset)
- cpu_pmu->reset(NULL);
-
return NOTIFY_OK;
}
@@ -777,24 +845,6 @@
}
}
-static int cpu_has_active_perf(void)
-{
- struct pmu_hw_events *hw_events;
- int enabled;
-
- if (!cpu_pmu)
- return 0;
-
- hw_events = cpu_pmu->get_hw_events();
- enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events);
-
- if (enabled)
- /*Even one event's existence is good enough.*/
- return 1;
-
- return 0;
-}
-
static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
.notifier_call = pmu_cpu_notify,
};
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 678c55d..58e9068 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -997,6 +997,7 @@
{
unsigned long flags;
struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ unsigned long long prev_count = local64_read(&hwc->prev_count);
/*
* Enable counter and interrupt, and set the counter to count
@@ -1022,6 +1023,9 @@
*/
armv7_pmnc_enable_intens(idx);
+ /* Restore prev val */
+ armv7pmu_write_counter(idx, prev_count & 0xffffffff);
+
/*
* Enable counter
*/
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0cf684d..5cf6bd2 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -289,6 +289,7 @@
select DONT_MAP_HOLE_AFTER_MEMBANK0
select SENSORS_ADSP
select MSM_ULTRASOUND_B
+ select MSM_LPM_TEST
config ARCH_MPQ8092
bool "MPQ8092"
@@ -393,6 +394,13 @@
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
select QMI_ENCDEC
+ select MSM_QDSP6_APRV2
+ select MSM_QDSP6V2_CODECS
+ select MSM_AUDIO_QDSP6V2 if SND_SOC
+ select MSM_RPM_SMD
+ select MSM_SPM_V2
+ select MSM_L2_SPM
+ select MSM_PM8X60 if PM
config ARCH_MSM8226
bool "MSM8226"
@@ -412,6 +420,10 @@
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
select QMI_ENCDEC
+ select MSM_RPM_SMD
+ select MSM_SPM_V2
+ select MSM_L2_SPM
+ select MSM_PM8X60 if PM
endmenu
choice
@@ -529,7 +541,7 @@
config MSM_LPM_TEST
bool "Low Power Mode test framework"
- depends on MSM_RPM
+ depends on MSM_RPM || MSM_RPM_SMD
depends on MSM_PM8X60
help
LPM_TEST is a test framework that assists in exercising the low
@@ -944,6 +956,15 @@
help
Support for the Qualcomm APQ8064 CDP device.
+config MACH_FSM8064_EP
+ depends on ARCH_APQ8064
+ bool "FSM8064 EP"
+ help
+ Support for the Qualcomm FSM8064 EP device.
+ This board also known as Femto development platform (FDP)
+ is based on APQ8064 chipset. This board does not support
+ keyboard, display or multimedia.
+
config MACH_APQ8064_MTP
depends on ARCH_APQ8064
bool "APQ8064 MTP"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 336c2fc..c4d9048 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -38,6 +38,7 @@
obj-$(CONFIG_ARCH_MSM9625) += pmu.o perf_event_msm_pl310.o
obj-$(CONFIG_ARCH_MSM8625) += pmu.o perf_event_msm_pl310.o
obj-$(CONFIG_ARCH_MSM9615) += pmu.o perf_event_msm_pl310.o
+obj-$(CONFIG_DEBUG_FS) += perf_debug.o
endif
ifndef CONFIG_MSM_SMP
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 377c4af..b451d08 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -47,21 +47,27 @@
# MSM8974
zreladdr-$(CONFIG_ARCH_MSM8974) := 0x00008000
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974-fluid.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974-liquid.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974-rumi.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974-sim.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-rumi.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-sim.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-mtp.dtb
# MSM9615
zreladdr-$(CONFIG_ARCH_MSM9615) := 0x40808000
# MSM9625
zreladdr-$(CONFIG_ARCH_MSM9625) := 0x00208000
- dtb-$(CONFIG_ARCH_MSM9625) += msm9625-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM9625) += msm9625-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM9625) += msm9625-rumi.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v1-rumi.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-mtp.dtb
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 359a156..a0727b7 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -650,6 +650,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index ac29cac..405b26b 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -142,6 +142,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index 40326cb..6915343 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -227,6 +227,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index 7d1ce09..9aebac9 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -203,6 +203,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
index 5003862..bddac00 100644
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ b/arch/arm/mach-msm/acpuclock-8930ab.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -257,6 +257,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index d7d3edd..317729f 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -210,6 +210,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index d2e88fb..38658a2 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -252,6 +252,7 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0x007000C0,
+ .get_bin_info = get_krait_bin_format_a,
.stby_khz = 384000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 94a4d3e..8eb4b28 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. 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
@@ -112,14 +112,14 @@
};
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 1050000, 0 },
- [1] = { { 345600, HFPLL, 2, 36 }, LVL_NOM, 1050000, 1 },
- [2] = { { 422400, HFPLL, 2, 44 }, LVL_NOM, 1050000, 1 },
- [3] = { { 499200, HFPLL, 2, 52 }, LVL_NOM, 1050000, 2 },
- [4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 1050000, 2 },
- [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 1050000, 3 },
- [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 1050000, 3 },
- [7] = { { 806400, HFPLL, 1, 42 }, LVL_NOM, 1050000, 3 },
+ [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
+ [1] = { { 345600, HFPLL, 2, 36 }, LVL_NOM, 950000, 1 },
+ [2] = { { 422400, HFPLL, 2, 44 }, LVL_NOM, 950000, 1 },
+ [3] = { { 499200, HFPLL, 2, 52 }, LVL_NOM, 950000, 2 },
+ [4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 950000, 2 },
+ [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 950000, 3 },
+ [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 950000, 3 },
+ [7] = { { 806400, HFPLL, 1, 42 }, LVL_HIGH, 1050000, 3 },
[8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 4 },
[9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 4 },
[10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 4 },
@@ -129,50 +129,135 @@
[14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 6 },
[15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 7 },
[16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- [17] = { { 1574400, HFPLL, 1, 82 }, LVL_HIGH, 1050000, 7 },
- [18] = { { 1651200, HFPLL, 1, 86 }, LVL_HIGH, 1050000, 7 },
- [19] = { { 1728000, HFPLL, 1, 90 }, LVL_HIGH, 1050000, 7 },
- [20] = { { 1804800, HFPLL, 1, 94 }, LVL_HIGH, 1050000, 7 },
- [21] = { { 1881600, HFPLL, 1, 98 }, LVL_HIGH, 1050000, 7 },
- [22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 7 },
- [23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 7 },
- [24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 7 },
- [25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 7 },
{ }
};
-static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 850000, 400000 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(0), 850000, 3200000 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(0), 850000, 3200000 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(0), 850000, 3200000 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(0), 850000, 3200000 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(16), 850000, 3200000 },
- { 0, { 729600, HFPLL, 1, 38 }, L2(16), 850000, 3200000 },
- { 1, { 806400, HFPLL, 1, 42 }, L2(16), 850000, 3200000 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(16), 870000, 3200000 },
- { 1, { 960000, HFPLL, 1, 50 }, L2(16), 880000, 3200000 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(16), 900000, 3200000 },
- { 1, { 1113600, HFPLL, 1, 58 }, L2(16), 915000, 3200000 },
- { 1, { 1190400, HFPLL, 1, 62 }, L2(16), 935000, 3200000 },
- { 1, { 1267200, HFPLL, 1, 66 }, L2(16), 950000, 3200000 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(16), 970000, 3200000 },
- { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 985000, 3200000 },
- { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 1000000, 3200000 },
+static struct acpu_level acpu_freq_tbl_pvs0[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(6), 825000, 3200000 },
+ { 0, { 729600, HFPLL, 1, 38 }, L2(6), 825000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(8), 835000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(8), 845000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(8), 860000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(8), 880000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 3200000 },
{ 1, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 3200000 },
{ 1, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 3200000 },
{ 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 3200000 },
- { 0, { 1804800, HFPLL, 1, 94 }, L2(16), 1050000, 3200000 },
- { 0, { 1881600, HFPLL, 1, 98 }, L2(16), 1050000, 3200000 },
- { 0, { 1958400, HFPLL, 1, 102 }, L2(16), 1050000, 3200000 },
- { 0, { 1996800, HFPLL, 1, 104 }, L2(16), 1050000, 3200000 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
- [0][PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
- [0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
- [0][PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+static struct acpu_level acpu_freq_tbl_pvs1[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(6), 825000, 3200000 },
+ { 0, { 729600, HFPLL, 1, 38 }, L2(6), 825000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(8), 835000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(8), 845000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(8), 860000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(8), 880000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 3200000 },
+ { 1, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 3200000 },
+ { 1, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_pvs2[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(6), 825000, 3200000 },
+ { 0, { 729600, HFPLL, 1, 38 }, L2(6), 825000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(8), 825000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(8), 825000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(8), 835000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(8), 855000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 3200000 },
+ { 1, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 3200000 },
+ { 1, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_pvs3[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(6), 825000, 3200000 },
+ { 0, { 729600, HFPLL, 1, 38 }, L2(6), 825000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(8), 825000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(8), 825000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(8), 835000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(8), 855000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 3200000 },
+ { 1, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 3200000 },
+ { 1, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_pvs4[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(6), 825000, 3200000 },
+ { 0, { 729600, HFPLL, 1, 38 }, L2(6), 825000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(8), 825000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(8), 825000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(8), 825000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(8), 825000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(12), 835000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(12), 855000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(12), 870000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 885000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(16), 900000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 3200000 },
+ { 1, { 1574400, HFPLL, 1, 82 }, L2(16), 925000, 3200000 },
+ { 1, { 1651200, HFPLL, 1, 86 }, L2(16), 940000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 950000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+ [0][0] = { acpu_freq_tbl_pvs0, sizeof(acpu_freq_tbl_pvs0) },
+ [0][1] = { acpu_freq_tbl_pvs1, sizeof(acpu_freq_tbl_pvs1) },
+ [0][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
+ [0][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
+ [0][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
};
static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
@@ -184,11 +269,41 @@
.l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0xFC4B80B0,
+ .get_bin_info = get_krait_bin_format_b,
.stby_khz = 300000,
};
+static void __init apply_l2_workaround(void)
+{
+ static struct l2_level resticted_l2_tbl[] __initdata = {
+ [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 1050000, 0 },
+ [1] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
+ { }
+ };
+ struct acpu_level *l;
+ int s, p;
+
+ for (s = 0; s < NUM_SPEED_BINS; s++)
+ for (p = 0; p < NUM_PVS; p++)
+ for (l = pvs_tables[s][p].table; l && l->speed.khz; l++)
+ l->l2_level = l->l2_level > 5 ? 1 : 0;
+
+ acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
+ acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
+}
+
static int __init acpuclk_8974_probe(struct platform_device *pdev)
{
+ /*
+ * 8974 hardware revisions older than v1.2 may experience L2 parity
+ * errors when running at some performance points between 300MHz
+ * and 1497.6MHz (non-inclusive), or when vdd_mx is less than 1.05V.
+ * Restrict L2 operation to safe performance points on these devices.
+ */
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2 &&
+ SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
+ apply_l2_workaround();
+
return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
}
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 10c4d6c..9566cea 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -1019,7 +1019,7 @@
.notifier_call = acpuclk_cpu_callback,
};
-static const int krait_needs_vmin(void)
+static const int __init krait_needs_vmin(void)
{
switch (read_cpuid_id()) {
case 0x511F04D0: /* KR28M2A20 */
@@ -1031,7 +1031,7 @@
};
}
-static void krait_apply_vmin(struct acpu_level *tbl)
+static void __init krait_apply_vmin(struct acpu_level *tbl)
{
for (; tbl->speed.khz != 0; tbl++) {
if (tbl->vdd_core < 1150000)
@@ -1040,62 +1040,78 @@
}
}
-static int __init get_speed_bin(u32 pte_efuse)
+void __init get_krait_bin_format_a(void __iomem *base, struct bin_info *bin)
{
- uint32_t speed_bin;
+ u32 pte_efuse = readl_relaxed(base);
- speed_bin = pte_efuse & 0xF;
- if (speed_bin == 0xF)
- speed_bin = (pte_efuse >> 4) & 0xF;
+ bin->speed = pte_efuse & 0xF;
+ if (bin->speed == 0xF)
+ bin->speed = (pte_efuse >> 4) & 0xF;
+ bin->speed_valid = bin->speed != 0xF;
- if (speed_bin == 0xF) {
- speed_bin = 0;
- dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n", speed_bin);
- } else {
- dev_info(drv.dev, "SPEED BIN: %d\n", speed_bin);
- }
-
- return speed_bin;
+ bin->pvs = (pte_efuse >> 10) & 0x7;
+ if (bin->pvs == 0x7)
+ bin->pvs = (pte_efuse >> 13) & 0x7;
+ bin->pvs_valid = bin->pvs != 0x7;
}
-static int __init get_pvs_bin(u32 pte_efuse)
+void __init get_krait_bin_format_b(void __iomem *base, struct bin_info *bin)
{
- uint32_t pvs_bin;
+ u32 pte_efuse, redundant_sel;
- pvs_bin = (pte_efuse >> 10) & 0x7;
- if (pvs_bin == 0x7)
- pvs_bin = (pte_efuse >> 13) & 0x7;
+ pte_efuse = readl_relaxed(base);
+ redundant_sel = (pte_efuse >> 24) & 0x7;
+ bin->speed = pte_efuse & 0x7;
+ bin->pvs = (pte_efuse >> 6) & 0x7;
- if (pvs_bin == 0x7) {
- pvs_bin = 0;
- dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n", pvs_bin);
- } else {
- dev_info(drv.dev, "ACPU PVS: %d\n", pvs_bin);
+ switch (redundant_sel) {
+ case 1:
+ bin->speed = (pte_efuse >> 27) & 0x7;
+ break;
+ case 2:
+ bin->pvs = (pte_efuse >> 27) & 0x7;
+ break;
}
+ bin->speed_valid = true;
- return pvs_bin;
+ /* Check PVS_BLOW_STATUS */
+ pte_efuse = readl_relaxed(base + 0x4);
+ bin->pvs_valid = !!(pte_efuse & BIT(21));
}
-static struct pvs_table * __init select_freq_plan(u32 pte_efuse_phys,
- struct pvs_table (*pvs_tables)[NUM_PVS])
+static struct pvs_table * __init select_freq_plan(
+ const struct acpuclk_krait_params *params)
{
- void __iomem *pte_efuse;
- u32 pte_efuse_val;
+ void __iomem *pte_efuse_base;
+ struct bin_info bin;
- pte_efuse = ioremap(pte_efuse_phys, 4);
- if (!pte_efuse) {
- dev_err(drv.dev, "Unable to map QFPROM base\n");
+ pte_efuse_base = ioremap(params->pte_efuse_phys, 8);
+ if (!pte_efuse_base) {
+ dev_err(drv.dev, "Unable to map PTE eFuse base\n");
return NULL;
}
+ params->get_bin_info(pte_efuse_base, &bin);
+ iounmap(pte_efuse_base);
- pte_efuse_val = readl_relaxed(pte_efuse);
- iounmap(pte_efuse);
+ if (bin.speed_valid) {
+ drv.speed_bin = bin.speed;
+ dev_info(drv.dev, "SPEED BIN: %d\n", drv.speed_bin);
+ } else {
+ drv.speed_bin = 0;
+ dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n",
+ drv.speed_bin);
+ }
- /* Select frequency tables. */
- drv.speed_bin = get_speed_bin(pte_efuse_val);
- drv.pvs_bin = get_pvs_bin(pte_efuse_val);
+ if (bin.pvs_valid) {
+ drv.pvs_bin = bin.pvs;
+ dev_info(drv.dev, "ACPU PVS: %d\n", drv.pvs_bin);
+ } else {
+ drv.pvs_bin = 0;
+ dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n",
+ drv.pvs_bin);
+ }
- return &pvs_tables[drv.speed_bin][drv.pvs_bin];
+ return ¶ms->pvs_tables[drv.speed_bin][drv.pvs_bin];
}
static void __init drv_data_init(struct device *dev,
@@ -1124,7 +1140,7 @@
GFP_KERNEL);
BUG_ON(!drv.bus_scale->usecase);
- pvs = select_freq_plan(params->pte_efuse_phys, params->pvs_tables);
+ pvs = select_freq_plan(params);
BUG_ON(!pvs->table);
drv.acpu_freq_tbl = kmemdup(pvs->table, pvs->size, GFP_KERNEL);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index ca8013e..00f64fc 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -152,7 +152,7 @@
struct acpu_level {
const int use_for_scaling;
const struct core_speed speed;
- const unsigned int l2_level;
+ unsigned int l2_level;
int vdd_core;
int ua_core;
unsigned int avsdscr_setting;
@@ -227,6 +227,20 @@
};
/**
+ * struct bin_info - Hardware speed and voltage binning info.
+ * @speed_valid: @speed field is valid
+ * @pvs_valid: @pvs field is valid
+ * @speed: Speed bin ID
+ * @pvs: PVS bin ID
+ */
+struct bin_info {
+ bool speed_valid;
+ bool pvs_valid;
+ int speed;
+ int pvs;
+};
+
+/**
* struct pvs_table - CPU performance level table and size.
* @table: CPU performance level table
* @size: sizeof(@table)
@@ -247,6 +261,7 @@
* @l2_freq_tbl: L2 frequency table.
* @l2_freq_tbl_size: Size of @l2_freq_tbl.
* @pte_efuse_phys: Physical address of PTE EFUSE.
+ * @get_bin_info: Function to populate bin_info from pte_efuse.
* @bus_scale: MSM bus driver parameters.
* @stby_khz: KHz value corresponding to an always-on clock source.
*/
@@ -258,6 +273,7 @@
struct l2_level *l2_freq_tbl;
size_t l2_freq_tbl_size;
phys_addr_t pte_efuse_phys;
+ void (*get_bin_info)(void __iomem *base, struct bin_info *bin);
struct msm_bus_scale_pdata *bus_scale;
unsigned long stby_khz;
};
@@ -297,6 +313,16 @@
};
/**
+ * get_krait_bin_format_a - Populate bin_info from a 'Format A' pte_efuse
+ */
+void __init get_krait_bin_format_a(void __iomem *base, struct bin_info *bin);
+
+/**
+ * get_krait_bin_format_b - Populate bin_info from a 'Format B' pte_efuse
+ */
+void __init get_krait_bin_format_b(void __iomem *base, struct bin_info *bin);
+
+/**
* acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
*/
extern int acpuclk_krait_init(struct device *dev,
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 040660a..9da5436 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -891,6 +891,7 @@
write_fail3:
kfree(pkt);
write_fail2:
+ skb_pull(skb, sizeof(struct bam_mux_hdr));
if (new_skb)
dev_kfree_skb_any(new_skb);
write_fail:
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 57d1b6c..0dee8f5 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -352,6 +352,18 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gsbi2_uart_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi4_uart_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting ext_regulator_config = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
@@ -716,6 +728,75 @@
},
};
+static struct msm_gpiomux_config fsm8064_ep_gsbi_configs[] __initdata = {
+ {
+ .gpio = 10, /* GSBI4 UART TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi4_uart_config,
+ },
+ },
+ {
+ .gpio = 11, /* GSBI4 UART RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi4_uart_config,
+ },
+ },
+ {
+ .gpio = 18, /* GSBI1 UART TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi1_uart_config,
+ },
+ },
+ {
+ .gpio = 19, /* GSBI1 UART RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi1_uart_config,
+ },
+ },
+ {
+ .gpio = 22, /* GSBI2 UART TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi2_uart_config,
+ },
+ },
+ {
+ .gpio = 23, /* GSBI7 UART2 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi2_uart_config,
+ },
+ },
+ {
+ .gpio = 51, /* GSBI5 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 52, /* GSBI5 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 53, /* Funny CS0 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 54, /* GSBI5 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 53, /* NOR CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
+};
+
static struct msm_gpiomux_config apq8064_non_mi2s_gsbi_configs[] __initdata = {
{
.gpio = 32, /* EPM CS */
@@ -1516,6 +1597,248 @@
},
};
+static struct gpiomux_setting boot_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm8064_ep_boot_configs[] __initdata = {
+ {
+ .gpio = 2,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 5,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 33,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 34,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 50,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+ {
+ .gpio = 87,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &boot_cfg,
+ },
+ },
+};
+
+static struct gpiomux_setting fsm8064_ep_backup_suspended_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config fsm8064_ep_backup_configs[] __initdata = {
+ {
+ .gpio = 45,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_backup_suspended_cfg,
+ },
+ },
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_backup_suspended_cfg,
+ },
+ },
+ {
+ .gpio = 47,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_backup_suspended_cfg,
+ },
+ },
+ {
+ .gpio = 62,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_backup_suspended_cfg,
+ },
+ },
+ {
+ .gpio = 82,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_backup_suspended_cfg,
+ },
+ },
+};
+
+static struct gpiomux_setting fsm8064_ep_uim_rst_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting fsm8064_ep_uim_pwr_sel_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct msm_gpiomux_config fsm8064_ep_uim_configs[] __initdata = {
+ {
+ .gpio = 49, /* UIM_RST */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_uim_rst_cfg,
+ },
+ },
+ {
+ .gpio = 55, /* UIM_PWR_SEL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_uim_pwr_sel_cfg,
+ },
+ },
+};
+
+static struct gpiomux_setting fsm8064_ep_sync_drsync_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct gpiomux_setting fsm8064_ep_sync_input_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm8064_ep_sync_configs[] __initdata = {
+ {
+ .gpio = 6, /* GPSPPSIN_DRSYNC */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_drsync_cfg,
+ },
+ },
+ {
+ .gpio = 7, /* KRAIT_PPS_INPUT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_input_cfg,
+ },
+ },
+ {
+ .gpio = 8, /* QDSP_PPS_INPUT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_input_cfg,
+ },
+ },
+ {
+ .gpio = 9, /* DAN_TTI_INPUT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_input_cfg,
+ },
+ },
+};
+
+static struct gpiomux_setting fsm8064_ep_led_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config fsm8064_ep_led_configs[] __initdata = {
+ {
+ .gpio = 58, /* RED1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 59, /* GREEN1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 60, /* RED2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 61, /* GREEN2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 69, /* RED3 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 70, /* GREEN3 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 71, /* RED4 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 72, /* GREEN4 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 77, /* RED5 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+ {
+ .gpio = 80, /* GREEN5 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &fsm8064_ep_led_cfg,
+ },
+ },
+};
+
void __init apq8064_init_gpiomux(void)
{
int rc;
@@ -1548,8 +1871,12 @@
ARRAY_SIZE(apq8064_ethernet_configs));
#endif
- msm_gpiomux_install(apq8064_gsbi_configs,
- ARRAY_SIZE(apq8064_gsbi_configs));
+ if (machine_is_fsm8064_ep())
+ msm_gpiomux_install(fsm8064_ep_gsbi_configs,
+ ARRAY_SIZE(fsm8064_ep_gsbi_configs));
+ else
+ msm_gpiomux_install(apq8064_gsbi_configs,
+ ARRAY_SIZE(apq8064_gsbi_configs));
if (!(machine_is_apq8064_mtp() &&
(SOCINFO_VERSION_MINOR(platform_version) == 1)))
@@ -1567,8 +1894,10 @@
msm_gpiomux_install(apq8064_gsbi1_i2c_2ma_configs,
ARRAY_SIZE(apq8064_gsbi1_i2c_2ma_configs));
} else {
- msm_gpiomux_install(apq8064_slimbus_config,
+ if (!machine_is_fsm8064_ep()) {
+ msm_gpiomux_install(apq8064_slimbus_config,
ARRAY_SIZE(apq8064_slimbus_config));
+ }
}
if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
@@ -1599,7 +1928,7 @@
msm_gpiomux_install(mpq8064_mi2s_configs,
ARRAY_SIZE(mpq8064_mi2s_configs));
- if (!machine_is_mpq8064_hrd())
+ if (!machine_is_mpq8064_hrd() && !machine_is_fsm8064_ep())
msm_gpiomux_install(apq8064_ext_regulator_configs,
ARRAY_SIZE(apq8064_ext_regulator_configs));
@@ -1632,8 +1961,9 @@
msm_gpiomux_install(apq8064_mxt_configs,
ARRAY_SIZE(apq8064_mxt_configs));
- msm_gpiomux_install(apq8064_hdmi_configs,
- ARRAY_SIZE(apq8064_hdmi_configs));
+ if (!machine_is_fsm8064_ep())
+ msm_gpiomux_install(apq8064_hdmi_configs,
+ ARRAY_SIZE(apq8064_hdmi_configs));
if (apq8064_mhl_display_enabled())
msm_gpiomux_install(apq8064_mhl_configs,
@@ -1665,4 +1995,17 @@
if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv())
msm_gpiomux_install(mpq8064_uartdm_configs,
ARRAY_SIZE(mpq8064_uartdm_configs));
+
+ if (machine_is_fsm8064_ep()) {
+ msm_gpiomux_install(fsm8064_ep_boot_configs,
+ ARRAY_SIZE(fsm8064_ep_boot_configs));
+ msm_gpiomux_install(fsm8064_ep_backup_configs,
+ ARRAY_SIZE(fsm8064_ep_backup_configs));
+ msm_gpiomux_install(fsm8064_ep_uim_configs,
+ ARRAY_SIZE(fsm8064_ep_uim_configs));
+ msm_gpiomux_install(fsm8064_ep_sync_configs,
+ ARRAY_SIZE(fsm8064_ep_sync_configs));
+ msm_gpiomux_install(fsm8064_ep_led_configs,
+ ARRAY_SIZE(fsm8064_ep_led_configs));
+ }
}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index aef937a..5322c87 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -130,6 +130,25 @@
PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30), /* PCIE_WAKE_N */
};
+static struct pm8xxx_gpio_init pm8921_fsm8064_ep_gpios[] __initdata = {
+ PM8921_GPIO_OUTPUT_VIN(1, 1, PM_GPIO_VIN_VPH), /* 5V reg */
+ PM8921_GPIO_OUTPUT_VIN(12, 1, PM_GPIO_VIN_VPH), /* 12V reg */
+ /* De-assert CW_GPS_RST_N for CW GPS module to lock to GPS source */
+ PM8921_GPIO_OUTPUT_VIN(14, 1, PM_GPIO_VIN_VPH),
+ /* PPS_SRC_SEL_N, chooses between WGR7640 PPS source (high) or
+ * CW GPS module PPS source (low) */
+ PM8921_GPIO_OUTPUT_VIN(19, 1, PM_GPIO_VIN_VPH), /* PPS_SRC_SEL_N */
+
+ PM8921_GPIO_OUTPUT_VIN(13, 1, PM_GPIO_VIN_VPH), /* PCIE_CLK_PWR_EN */
+ PM8921_GPIO_OUTPUT_VIN(37, 1, PM_GPIO_VIN_VPH), /* PCIE_RST_N */
+ PM8921_GPIO_INPUT(11, PM_GPIO_PULL_UP_30), /* PCIE_WAKE_N */
+
+ PM8921_GPIO_OUTPUT_VIN(23, 1, PM_GPIO_VIN_VPH), /* USB2_HSIC_RST_N */
+
+ PM8921_GPIO_OUTPUT_VIN(24, 1, PM_GPIO_VIN_VPH), /* USB3_RST_N */
+ PM8921_GPIO_OUTPUT_VIN(34, 1, PM_GPIO_VIN_VPH), /* USB4_RST_N */
+};
+
static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
PM8921_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
PM8921_GPIO_INPUT(4, PM_GPIO_PULL_UP_30),
@@ -209,10 +228,16 @@
{
int i, rc;
- if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
- apq8064_configure_gpios(pm8921_gpios, ARRAY_SIZE(pm8921_gpios));
- else
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+ if (machine_is_fsm8064_ep())
+ apq8064_configure_gpios(pm8921_fsm8064_ep_gpios,
+ ARRAY_SIZE(pm8921_fsm8064_ep_gpios));
+ else
+ apq8064_configure_gpios(pm8921_gpios,
+ ARRAY_SIZE(pm8921_gpios));
+ } else {
apq8064_configure_gpios(pm8917_gpios, ARRAY_SIZE(pm8917_gpios));
+ }
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid()) {
apq8064_configure_gpios(touchscreen_gpios,
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 16b53fb..57ecc27 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -458,6 +458,16 @@
.active_low = _active_low, \
}
+#define FIXED_VREG_INIT(_id, _supply_regulator) \
+ { \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ }, \
+ .num_consumer_supplies = ARRAY_SIZE(vreg_consumers_##_id), \
+ .consumer_supplies = vreg_consumers_##_id, \
+ .supply_regulator = _supply_regulator, \
+ }
+
#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
{ \
.constraints = { \
@@ -597,6 +607,17 @@
SX150X_GPIO(4, 15), "avc_5v", 0),
};
+/* Fixed regulator constraints */
+static struct regulator_init_data mpq8064_3p3_regulator_init =
+ /* ID supply */
+ FIXED_VREG_INIT(EXT_3P3V, NULL);
+
+struct fixed_voltage_config mpq8064_3p3_regulator_pdata = {
+ .supply_name = "ext_3p3v",
+ .gpio = -EINVAL,
+ .init_data = &mpq8064_3p3_regulator_init,
+};
+
/* SAW regulator constraints */
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
/* ID vreg_name min_uV max_uV */
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 3fe0838..dc9120a 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -143,6 +143,11 @@
#define PCIE_PWR_EN_PMIC_GPIO 13
#define PCIE_RST_N_PMIC_MPP 1
+/* PCIe pmic gpios for fsm8064_ep */
+/* Unused pin. The WAKE feature is not supported on fsm8064_ep */
+#define PCIE_EP_WAKE_N_PMIC_GPIO 11
+#define PCIE_EP_RST_N_PMIC_GPIO 37
+
#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
static int __init msm_contig_mem_size_setup(char *p)
@@ -959,7 +964,7 @@
{
if (machine_is_apq8064_liquid() || machine_is_mpq8064_cdp() ||
machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv() ||
- machine_is_apq8064_cdp()) {
+ machine_is_apq8064_cdp() || machine_is_fsm8064_ep()) {
if (machine_is_apq8064_liquid())
msm_ehci_host_pdata3.dock_connect_irq =
PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
@@ -2073,9 +2078,8 @@
{
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_apq8064_io();
-
- if (IS_ERR_OR_NULL(socinfo_init()))
- pr_err("socinfo_init() failed!\n");
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
}
static void __init apq8064_init_irq(void)
@@ -2480,6 +2484,19 @@
.wake_n = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PCIE_WAKE_N_PMIC_GPIO),
};
+/* FSM8064_EP PCIe gpios */
+static struct msm_pcie_gpio_info_t ep_pcie_gpio_info[MSM_PCIE_MAX_GPIO] = {
+ {"rst_n", PM8921_GPIO_PM_TO_SYS(PCIE_EP_RST_N_PMIC_GPIO), 0},
+ {"pwr_en", PM8921_GPIO_PM_TO_SYS(PCIE_PWR_EN_PMIC_GPIO), 1},
+};
+
+static struct msm_pcie_platform ep_pcie_platform_data = {
+ .gpio = ep_pcie_gpio_info,
+ .axi_addr = PCIE_AXI_BAR_PHYS,
+ .axi_size = PCIE_AXI_BAR_SIZE,
+ .wake_n = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PCIE_EP_WAKE_N_PMIC_GPIO),
+};
+
static int __init mpq8064_pcie_enabled(void)
{
return !((readl_relaxed(QFPROM_RAW_FEAT_CONFIG_ROW0_MSB) & BIT(21)) ||
@@ -2494,6 +2511,19 @@
}
}
+static void __init fsm8064_ep_pcie_init(void)
+{
+ msm_device_pcie.dev.platform_data = &ep_pcie_platform_data;
+ platform_device_register(&msm_device_pcie);
+}
+
+static struct platform_device mpq8064_device_ext_3p3v_vreg = {
+ .name = "reg-fixed-voltage",
+ .dev = {
+ .platform_data = &mpq8064_3p3_regulator_pdata,
+ },
+};
+
static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
.name = GPIO_REGULATOR_DEV_NAME,
.id = PM8921_MPP_PM_TO_SYS(7),
@@ -2582,6 +2612,100 @@
&mpq_cpudai_pseudo,
};
+static struct platform_device *ep_devices[] __initdata = {
+ &msm_device_smd_apq8064,
+ &apq8064_device_gadget_peripheral,
+ &apq8064_device_hsusb_host,
+ &android_usb_device,
+ &msm_device_wcnss_wlan,
+ &msm_device_iris_fm,
+ &apq8064_fmem_device,
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ &apq8064_android_pmem_device,
+ &apq8064_android_pmem_adsp_device,
+ &apq8064_android_pmem_audio_device,
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+#ifdef CONFIG_ION_MSM
+ &apq8064_ion_dev,
+#endif
+ &msm8064_device_watchdog,
+ &msm8064_device_saw_regulator_core0,
+ &msm8064_device_saw_regulator_core1,
+ &msm8064_device_saw_regulator_core2,
+ &msm8064_device_saw_regulator_core3,
+#if defined(CONFIG_QSEECOM)
+ &qseecom_device,
+#endif
+
+ &msm_8064_device_tsif[0],
+ &msm_8064_device_tsif[1],
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
+
+#ifdef CONFIG_HW_RANDOM_MSM
+ &apq8064_device_rng,
+#endif
+ &apq_pcm,
+ &apq_pcm_routing,
+ &apq8064_rpm_device,
+ &apq8064_rpm_log_device,
+ &apq8064_rpm_stat_device,
+ &apq8064_rpm_master_stat_device,
+ &apq_device_tz_log,
+ &msm_bus_8064_apps_fabric,
+ &msm_bus_8064_sys_fabric,
+ &msm_bus_8064_mm_fabric,
+ &msm_bus_8064_sys_fpb,
+ &msm_bus_8064_cpss_fpb,
+ &msm_pil_dsps,
+ &msm_8960_q6_lpass,
+ &msm_pil_vidc,
+ &msm_gss,
+ &apq8064_rtb_device,
+ &apq8064_dcvs_device,
+ &apq8064_msm_gov_device,
+ &apq8064_device_cache_erp,
+ &msm8960_device_ebi1_ch0_erp,
+ &msm8960_device_ebi1_ch1_erp,
+ &epm_adc_device,
+ &coresight_tpiu_device,
+ &coresight_etb_device,
+ &apq8064_coresight_funnel_device,
+ &coresight_etm0_device,
+ &coresight_etm1_device,
+ &coresight_etm2_device,
+ &coresight_etm3_device,
+#ifdef CONFIG_MSM_GEMINI
+ &msm8960_gemini_device,
+#endif
+ &msm_tsens_device,
+ &apq8064_cache_dump_device,
+ &msm_8064_device_tspp,
+#ifdef CONFIG_BATTERY_BCL
+ &battery_bcl_device,
+#endif
+ &apq8064_msm_mpd_device,
+ &apq8064_device_qup_i2c_gsbi1,
+ &apq8064_device_uart_gsbi2,
+ &apq8064_device_uart_gsbi1,
+ &apq8064_device_uart_gsbi4,
+ &msm_device_sps_apq8064,
+#ifdef CONFIG_MSM_ROTATOR
+ &msm_rotator_device,
+#endif
+ &msm8064_pc_cntr,
+};
+
static struct platform_device *common_i2s_devices[] __initdata = {
&apq_cpudai_mi2s,
&apq_cpudai_i2s_rx,
@@ -2605,6 +2729,7 @@
static struct platform_device *pm8921_mpq_hrd_common_devices[] __initdata = {
&apq8064_device_ext_5v_vreg,
&apq8064_device_ext_mpp8_vreg,
+ &mpq8064_device_ext_3p3v_vreg,
&apq8064_device_ssbi_pmic1,
&apq8064_device_ssbi_pmic2,
};
@@ -2991,12 +3116,14 @@
wmb();
iounmap(gsbi_mem);
apq8064_i2c_qup_gsbi1_pdata.use_gsbi_shared_mode = 1;
- apq8064_device_qup_i2c_gsbi3.dev.platform_data =
- &apq8064_i2c_qup_gsbi3_pdata;
apq8064_device_qup_i2c_gsbi1.dev.platform_data =
&apq8064_i2c_qup_gsbi1_pdata;
- apq8064_device_qup_i2c_gsbi4.dev.platform_data =
- &apq8064_i2c_qup_gsbi4_pdata;
+ if (!machine_is_fsm8064_ep()) {
+ apq8064_device_qup_i2c_gsbi3.dev.platform_data =
+ &apq8064_i2c_qup_gsbi3_pdata;
+ apq8064_device_qup_i2c_gsbi4.dev.platform_data =
+ &apq8064_i2c_qup_gsbi4_pdata;
+ }
mpq8064_device_qup_i2c_gsbi5.dev.platform_data =
&mpq8064_i2c_qup_gsbi5_pdata;
}
@@ -3512,6 +3639,8 @@
mach_mask = I2C_LIQUID;
else if (PLATFORM_IS_MPQ8064())
mach_mask = I2C_MPQ_CDP;
+ else if (machine_is_fsm8064_ep())
+ mach_mask = I2C_SURF;
else
pr_err("unmatched machine ID in register_i2c_devices\n");
@@ -3580,7 +3709,7 @@
platform_device_register(&msm_gpio_device);
msm_tsens_early_init(&apq_tsens_pdata);
msm_thermal_init(&msm_thermal_pdata);
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
BUG_ON(msm_rpm_init(&apq8064_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
@@ -3637,9 +3766,11 @@
ARRAY_SIZE(pm8917_common_devices));
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
platform_device_register(&apq8064_device_ext_ts_sw_vreg);
- platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ if (!machine_is_fsm8064_ep())
+ platform_add_devices(common_devices,
+ ARRAY_SIZE(common_devices));
if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
- machine_is_mpq8064_dtv()))
+ machine_is_mpq8064_dtv() || machine_is_fsm8064_ep()))
platform_add_devices(common_not_mpq_devices,
ARRAY_SIZE(common_not_mpq_devices));
@@ -3790,6 +3921,26 @@
}
}
+static void __init fsm8064_ep_init(void)
+{
+ if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
+ pr_err("meminfo_init() failed!\n");
+
+ apq8064_common_init();
+ ethernet_init();
+ msm_rotator_set_split_iommu_domain();
+ fsm8064_ep_pcie_init();
+ platform_add_devices(ep_devices, ARRAY_SIZE(ep_devices));
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+ apq8064_init_gpu();
+ platform_add_devices(apq8064_footswitch, apq8064_num_footswitch);
+ platform_device_register(&cdp_kp_pdev);
+#ifdef CONFIG_MSM_CAMERA
+ apq8064_init_cam();
+#endif
+ change_memory_power = &apq8064_change_memory_power;
+}
+
MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
.map_io = apq8064_map_io,
.reserve = apq8064_reserve,
@@ -3803,6 +3954,18 @@
.smp = &msm8960_smp_ops,
MACHINE_END
+MACHINE_START(FSM8064_EP, "QCT FSM8064 EP")
+ .map_io = apq8064_map_io,
+ .reserve = apq8064_reserve,
+ .init_irq = apq8064_init_irq,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_timer,
+ .init_machine = fsm8064_ep_init,
+ .init_early = apq8064_allocate_memory_regions,
+ .init_very_early = apq8064_early_reserve,
+ .restart = msm_restart,
+MACHINE_END
+
MACHINE_START(APQ8064_MTP, "QCT APQ8064 MTP")
.map_io = apq8064_map_io,
.reserve = apq8064_reserve,
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 4cdf939..adc037b 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -14,6 +14,7 @@
#define __ARCH_ARM_MACH_MSM_BOARD_APQ8064_H
#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/regulator/fixed.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/pm8821.h>
#include <mach/msm_memtypes.h>
@@ -65,6 +66,8 @@
extern struct gpio_regulator_platform_data
mpq8064_gpio_regulator_pdata[] __devinitdata;
+extern struct fixed_voltage_config mpq8064_3p3_regulator_pdata;
+
extern struct rpm_regulator_platform_data
apq8064_rpm_regulator_pdata __devinitdata;
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index c7d01bf..b4c63f9 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -96,10 +96,8 @@
static void __init mpq8092_init(void)
{
struct of_dev_auxdata *adata = mpq8092_auxdata_lookup;
- struct device *parent;
- parent = socinfo_init();
- if (IS_ERR_OR_NULL(parent))
+ if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
mpq8092_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 0f8bfd4..3a6eb7f 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -42,9 +42,14 @@
#include <mach/socinfo.h>
#include <mach/board.h>
#include <mach/clk-provider.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <linux/msm_thermal.h>
#include "board-dt.h"
#include "clock.h"
#include "platsmp.h"
+#include "spm.h"
+#include "lpm_resources.h"
static struct memtype_reserve msm8226_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -121,19 +126,27 @@
msm_reserve();
}
+
+void __init msm8226_add_drivers(void)
+{
+ msm_rpm_driver_init();
+ msm_lpmrs_module_init();
+ msm_spm_device_init();
+ msm_thermal_device_init();
+}
+
void __init msm8226_init(void)
{
struct of_dev_auxdata *adata = msm8226_auxdata_lookup;
- struct device *parent;
- parent = socinfo_init();
- if (IS_ERR_OR_NULL(parent))
+ if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
msm8226_init_gpiomux();
-
+ msm8226_add_drivers();
msm_clock_init(&msm_dummy_clock_init_data);
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+
}
static const char *msm8226_dt_match[] __initconst = {
@@ -143,7 +156,7 @@
DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8226 (Flattened Device Tree)")
.map_io = msm_map_msm8226_io,
- .init_irq = msm_dt_init_irq_nompm,
+ .init_irq = msm_dt_init_irq,
.init_machine = msm8226_init,
.handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 91d7863..322d696 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -40,9 +40,14 @@
#include <mach/socinfo.h>
#include <mach/board.h>
#include <mach/clk-provider.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <linux/msm_thermal.h>
#include "board-dt.h"
#include "clock.h"
#include "platsmp.h"
+#include "spm.h"
+#include "lpm_resources.h"
static struct memtype_reserve msm8610_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -84,21 +89,29 @@
msm_reserve();
}
+void __init msm8610_add_drivers(void)
+{
+ msm_rpm_driver_init();
+ msm_lpmrs_module_init();
+ msm_spm_device_init();
+ msm_thermal_device_init();
+}
+
void __init msm8610_init(void)
{
struct of_dev_auxdata *adata = msm8610_auxdata_lookup;
- struct device *parent;
- parent = socinfo_init();
- if (IS_ERR_OR_NULL(parent))
+ if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
msm8610_init_gpiomux();
+ msm8610_add_drivers();
if (machine_is_msm8610_rumi())
msm_clock_init(&msm8610_rumi_clock_init_data);
else
msm_clock_init(&msm8610_clock_init_data);
+
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
}
@@ -109,7 +122,7 @@
DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8610 (Flattened Device Tree)")
.map_io = msm_map_msm8610_io,
- .init_irq = msm_dt_init_irq_nompm,
+ .init_irq = msm_dt_init_irq,
.init_machine = msm8610_init,
.handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index c8e493c..0c6a271 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -146,7 +146,7 @@
.set_grp_async = NULL,
.idle_timeout = HZ/12,
.nap_allowed = true,
- .strtstp_sleepwake = true,
+ .strtstp_sleepwake = false,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp3d_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 194c77f..6323c49 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -1465,7 +1465,7 @@
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm8930_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
@@ -2502,7 +2502,6 @@
&msm_pcm_hostless,
&msm_multi_ch_pcm,
&msm_lowlatency_pcm,
- &msm_fm_loopback,
};
static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index f6b62f9..bfabb9a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1393,6 +1393,8 @@
static struct mdm_platform_data sglte_platform_data = {
.mdm_version = "4.0",
.ramdump_delay_ms = 1000,
+ /* delay between two PS_HOLDs */
+ .ps_hold_delay_ms = 500,
.soft_reset_inverted = 1,
.peripheral_platform_device = NULL,
.ramdump_timeout_ms = 600000,
@@ -1510,7 +1512,7 @@
{
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm8960_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index b1e107d..ac93b00 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. 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
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index b90d75b..2fdceae 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -300,6 +300,8 @@
static struct of_dev_auxdata msm8974_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
"msm_otg", NULL),
+ OF_DEV_AUXDATA("qcom,ehci-host", 0xF9A55000, \
+ "msm_ehci_host", NULL),
OF_DEV_AUXDATA("qcom,dwc-usb3-msm", 0xF9200000, \
"msm_dwc3", NULL),
OF_DEV_AUXDATA("qcom,usb-bam-msm", 0xF9304000, \
@@ -364,10 +366,8 @@
void __init msm8974_init(void)
{
struct of_dev_auxdata *adata = msm8974_auxdata_lookup;
- struct device *parent;
- parent = socinfo_init();
- if (IS_ERR_OR_NULL(parent))
+ if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
msm_8974_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 07c37dd..9b02a5d 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -112,6 +112,8 @@
"msm-tsens", NULL),
OF_DEV_AUXDATA("qcom,usb-bam-msm", 0xF9A44000, \
"usb_bam", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A15000, \
+ "msm_hsic_host", NULL),
{}
};
@@ -237,10 +239,7 @@
void __init msm9625_init(void)
{
- struct device *parent;
-
- parent = socinfo_init();
- if (IS_ERR_OR_NULL(parent))
+ if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
msm9625_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 74b0d0d..5d2fdf9 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -14,13 +14,16 @@
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_fdt.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <asm/arch_timer.h>
#include <asm/mach/time.h>
+#include <asm/mach/map.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
#include <mach/mpm.h>
#include <mach/qpnp-int.h>
+#include <mach/msm_iomap.h>
#include <mach/scm.h>
#include "board-dt.h"
@@ -75,3 +78,40 @@
l2x0_of_init(0, ~0UL);
msm_dt_init_irq();
}
+
+int __init msm_scan_dt_map_imem(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ unsigned int *imem_prop;
+ unsigned long imem_prop_len;
+ struct map_desc map;
+ int ret;
+ const char *compat = "qcom,msm-imem";
+
+ ret = of_flat_dt_is_compatible(node, compat);
+
+ if (!ret)
+ return 0;
+
+ imem_prop = of_get_flat_dt_prop(node, "reg",
+ &imem_prop_len);
+
+ if (!imem_prop) {
+ WARN(1, "IMEM reg field not found\n");
+ return 0;
+ }
+
+ if (imem_prop_len != (2*sizeof(u32))) {
+ WARN(1, "IMEM range malformed\n");
+ return 0;
+ }
+
+ map.virtual = (unsigned long)MSM_IMEM_BASE;
+ map.pfn = __phys_to_pfn(be32_to_cpu(imem_prop[0]));
+ map.length = be32_to_cpu(imem_prop[1]);
+ map.type = MT_DEVICE;
+ iotable_init(&map, 1);
+ pr_info("IMEM DT static mapping successful\n");
+
+ return 1;
+}
diff --git a/arch/arm/mach-msm/board-dt.h b/arch/arm/mach-msm/board-dt.h
index cc3e92c..03ffa0b 100644
--- a/arch/arm/mach-msm/board-dt.h
+++ b/arch/arm/mach-msm/board-dt.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
@@ -14,3 +14,5 @@
void __init msm_dt_init_irq(void);
void __init msm_dt_init_irq_nompm(void);
void __init msm_dt_init_irq_l2x0(void);
+int __init msm_scan_dt_map_imem(unsigned long node, const char *uname,
+ int depth, void *data);
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 16740b2..cb2e766 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -1002,7 +1002,7 @@
{
msm_shared_ram_phys = 0x00100000;
msm_map_fsm9xxx_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 752c99a..0654a0d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -7349,7 +7349,7 @@
{
msm_shared_ram_phys = 0x00100000;
msm_map_msm7x30_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e678dfb..c45cf11 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -7541,7 +7541,7 @@
{
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm8x60_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 57c548e..e3b42bc 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2521,7 +2521,7 @@
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_qsd8x50_io();
qsd8x50_allocate_memory_regions();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 30229e1..159f151 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -1272,6 +1272,8 @@
.cbcr_reg = LPASS_Q6_AXI_CBCR,
.has_sibling = 1,
.base = &virt_bases[GCC_BASE],
+ /* FIXME: Remove this once simulation is fixed. */
+ .halt_check = DELAY,
.c = {
.dbg_name = "gcc_lpass_q6_axi_clk",
.ops = &clk_ops_branch,
@@ -1735,6 +1737,8 @@
.cbcr_reg = BIMC_GFX_CBCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
+ /* FIXME: Remove this once simulation is fixed. */
+ .halt_check = DELAY,
.c = {
.dbg_name = "bimc_gfx_clk",
.ops = &clk_ops_branch,
@@ -1843,7 +1847,7 @@
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &csi0_clk_src.c,
+ .parent = &csi1_clk_src.c,
.dbg_name = "csi1pix_clk",
.ops = &clk_ops_branch,
CLK_INIT(csi1pix_clk.c),
@@ -1855,7 +1859,7 @@
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &csi0_clk_src.c,
+ .parent = &csi1_clk_src.c,
.dbg_name = "csi1rdi_clk",
.ops = &clk_ops_branch,
CLK_INIT(csi1rdi_clk.c),
@@ -1995,6 +1999,8 @@
.cbcr_reg = MDP_AXI_CBCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
+ /* FIXME: Remove this once simulation is fixed. */
+ .halt_check = DELAY,
.c = {
.parent = &axi_clk_src.c,
.dbg_name = "mdp_axi_clk",
@@ -2148,6 +2154,8 @@
.cbcr_reg = VFE_AXI_CBCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
+ /* FIXME: Remove this once simulation is fixed. */
+ .halt_check = DELAY,
.c = {
.parent = &axi_clk_src.c,
.dbg_name = "vfe_axi_clk",
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 928b5aa..01ccb5e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -85,7 +85,12 @@
#define BB_PLL8_CONFIG_REG REG(0x3154)
#define BB_PLL8_TEST_CTL_REG REG(0x3150)
#define BB_MMCC_PLL2_MODE_REG REG(0x3160)
+#define BB_MMCC_PLL2_L_REG REG(0x3164)
+#define BB_MMCC_PLL2_M_REG REG(0x3168)
+#define BB_MMCC_PLL2_N_REG REG(0x316C)
#define BB_MMCC_PLL2_TEST_CTL_REG REG(0x3170)
+#define BB_MMCC_PLL2_CONFIG_REG REG(0x3174)
+#define BB_MMCC_PLL2_STATUS_REG REG(0x3178)
#define BB_PLL14_MODE_REG REG(0x31C0)
#define BB_PLL14_L_VAL_REG REG(0x31C4)
#define BB_PLL14_M_VAL_REG REG(0x31C8)
@@ -3049,22 +3054,30 @@
return -ENXIO;
}
-static enum handoff pix_rdi_clk_handoff(struct clk *c)
+static struct clk *pix_rdi_clk_get_parent(struct clk *c)
{
u32 reg;
struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+
+ reg = readl_relaxed(rdi->s_reg);
+ rdi->cur_rate = reg & rdi->s_mask ? 1 : 0;
+ reg = readl_relaxed(rdi->s2_reg);
+ rdi->cur_rate = reg & rdi->s2_mask ? 2 : rdi->cur_rate;
+
+ return pix_rdi_mux_map[rdi->cur_rate];
+}
+
+static enum handoff pix_rdi_clk_handoff(struct clk *c)
+{
+ struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
enum handoff ret;
ret = branch_handoff(&rdi->b, &rdi->c);
if (ret == HANDOFF_DISABLED_CLK)
return ret;
- reg = readl_relaxed(rdi->s_reg);
- rdi->cur_rate = reg & rdi->s_mask ? 1 : 0;
- reg = readl_relaxed(rdi->s2_reg);
- rdi->cur_rate = reg & rdi->s2_mask ? 2 : rdi->cur_rate;
- c->parent = pix_rdi_mux_map[rdi->cur_rate];
-
+ rdi->prepared = true;
+ rdi->enabled = true;
return HANDOFF_ENABLED_CLK;
}
@@ -3078,6 +3091,7 @@
.get_rate = pix_rdi_clk_get_rate,
.list_rate = pix_rdi_clk_list_rate,
.reset = pix_rdi_clk_reset,
+ .get_parent = pix_rdi_clk_get_parent,
};
static struct pix_rdi_clk csi_pix_clk = {
@@ -3509,7 +3523,7 @@
.ctl_val = CC_BANKED(9, 6, n), \
}
-/*Shared by 8064, 8930, and 8960ab*/
+/*Shared by 8064, and 8930*/
static struct clk_freq_tbl clk_tbl_gfx3d[] = {
F_GFX3D( 0, gnd, 0, 0),
F_GFX3D( 27000000, pxo, 0, 0),
@@ -3532,6 +3546,28 @@
F_END
};
+static struct clk_freq_tbl clk_tbl_gfx3d_8960ab[] = {
+ F_GFX3D( 0, gnd, 0, 0),
+ F_GFX3D( 27000000, pxo, 0, 0),
+ F_GFX3D( 48000000, pll8, 1, 8),
+ F_GFX3D( 54857000, pll8, 1, 7),
+ F_GFX3D( 64000000, pll8, 1, 6),
+ F_GFX3D( 76800000, pll8, 1, 5),
+ F_GFX3D( 96000000, pll8, 1, 4),
+ F_GFX3D(128000000, pll8, 1, 3),
+ F_GFX3D(145455000, pll2, 2, 11),
+ F_GFX3D(160000000, pll2, 1, 5),
+ F_GFX3D(177778000, pll2, 2, 9),
+ F_GFX3D(192000000, pll8, 1, 2),
+ F_GFX3D(200000000, pll2, 1, 4),
+ F_GFX3D(228571000, pll2, 2, 7),
+ F_GFX3D(266667000, pll2, 1, 3),
+ F_GFX3D(320000000, pll2, 2, 5),
+ F_GFX3D(400000000, pll2, 1, 2),
+ F_GFX3D(440000000, pll3, 1, 2),
+ F_END
+};
+
static struct clk_freq_tbl clk_tbl_gfx3d_8960[] = {
F_GFX3D( 0, gnd, 0, 0),
F_GFX3D( 27000000, pxo, 0, 0),
@@ -3605,6 +3641,23 @@
[VDD_DIG_HIGH] = 500000000
};
+static unsigned long fmax_gfx3d_8960ab_400[VDD_DIG_NUM] = {
+ [VDD_DIG_LOW] = 192000000,
+ [VDD_DIG_NOMINAL] = 325000000,
+ [VDD_DIG_HIGH] = 400000000
+};
+
+static unsigned long fmax_gfx3d_8960ab_440[VDD_DIG_NUM] = {
+ [VDD_DIG_LOW] = 192000000,
+ [VDD_DIG_NOMINAL] = 325000000,
+ [VDD_DIG_HIGH] = 440000000
+};
+
+static unsigned long *fmax_gfx3d_8960ab[] = {
+ [0] = fmax_gfx3d_8960ab_400,
+ [1] = fmax_gfx3d_8960ab_440,
+};
+
static struct bank_masks bmnd_info_gfx3d = {
.bank_sel_mask = BIT(11),
.bank0_mask = {
@@ -3837,26 +3890,6 @@
.ns_val = NS_MND_BANKED8(22, 14, n, m, 3, 0, s##_to_mm_mux), \
.ctl_val = CC_BANKED(9, 6, n), \
}
-static struct clk_freq_tbl clk_tbl_mdp_8960ab[] = {
- F_MDP( 0, gnd, 0, 0),
- F_MDP( 9600000, pll8, 1, 40),
- F_MDP( 13710000, pll8, 1, 28),
- F_MDP( 27000000, pxo, 0, 0),
- F_MDP( 29540000, pll8, 1, 13),
- F_MDP( 34910000, pll8, 1, 11),
- F_MDP( 38400000, pll8, 1, 10),
- F_MDP( 59080000, pll8, 2, 13),
- F_MDP( 76800000, pll8, 1, 5),
- F_MDP( 85330000, pll8, 2, 9),
- F_MDP( 96000000, pll8, 1, 4),
- F_MDP(128000000, pll8, 1, 3),
- F_MDP(160000000, pll2, 1, 5),
- F_MDP(177780000, pll2, 2, 9),
- F_MDP(200000000, pll2, 1, 4),
- F_MDP(228571000, pll2, 2, 7),
- F_MDP(266667000, pll2, 1, 3),
- F_END
-};
static struct clk_freq_tbl clk_tbl_mdp[] = {
F_MDP( 0, gnd, 0, 0),
@@ -3874,6 +3907,7 @@
F_MDP(160000000, pll2, 1, 5),
F_MDP(177780000, pll2, 2, 9),
F_MDP(200000000, pll2, 1, 4),
+ F_MDP(228571000, pll2, 2, 7),
F_MDP(266667000, pll2, 1, 3),
F_END
};
@@ -3927,6 +3961,11 @@
},
};
+static unsigned long fmax_mdp_8960ab[VDD_DIG_NUM] = {
+ [VDD_DIG_LOW] = 128000000,
+ [VDD_DIG_NOMINAL] = 266667000
+};
+
static struct branch_clk lut_mdp_clk = {
.b = {
.ctl_reg = MDP_LUT_CC_REG,
@@ -5283,8 +5322,10 @@
CLK_LOOKUP("core_clk", gp2_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi1_uart_clk.c, "msm_serial_hsl.1"),
CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, ""),
+ CLK_LOOKUP("core_clk", gsbi2_uart_clk.c, "msm_serial_hsl.3"),
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi4_uart_clk.c, ""),
+ CLK_LOOKUP("core_clk", gsbi4_uart_clk.c, "msm_serial_hsl.4"),
CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, "msm_serial_hsl.2"),
CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("core_clk", gsbi7_uart_clk.c, "msm_serial_hsl.0"),
@@ -5332,6 +5373,7 @@
CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, "msm_serial_hsl.1"),
CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, "qup_i2c.0"),
CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, "msm_serial_hsl.3"),
CLK_LOOKUP("iface_clk", gsbi3_p_clk.c, "qup_i2c.3"),
CLK_LOOKUP("iface_clk", gsbi4_p_clk.c, "qup_i2c.4"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "msm_serial_hsl.2"),
@@ -5340,6 +5382,7 @@
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "spi_qsd.1"),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, "msm_serial_hsl.0"),
+ CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, "msm_serial_hsl.4"),
CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tspp.0"),
CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tspp.0"),
CLK_LOOKUP("iface_clk", usb_fs1_p_clk.c, ""),
@@ -6270,6 +6313,31 @@
writel_relaxed(regval, reg);
}
+static struct pll_config_regs pll3_regs __initdata = {
+ .l_reg = BB_MMCC_PLL2_L_REG,
+ .m_reg = BB_MMCC_PLL2_M_REG,
+ .n_reg = BB_MMCC_PLL2_N_REG,
+ .config_reg = BB_MMCC_PLL2_CONFIG_REG,
+ .mode_reg = BB_MMCC_PLL2_MODE_REG,
+};
+
+/* Program PLL3 to 880MHZ */
+static struct pll_config pll3_config __initdata = {
+ .l = (32 | BVAL(31, 7, 0x8)),
+ .m = 16,
+ .n = 27,
+ .vco_val = 0x0,
+ .vco_mask = BM(8, 7),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BIT(15),
+ .post_div_val = 0x0,
+ .post_div_mask = BIT(16),
+ .mn_ena_val = 0,
+ .mn_ena_mask = 0,
+ .main_output_val = 0,
+ .main_output_mask = 0,
+};
+
static struct pll_config_regs pll4_regs __initdata = {
.l_reg = LCC_PLL0_L_VAL_REG,
.m_reg = LCC_PLL0_M_VAL_REG,
@@ -6369,7 +6437,7 @@
writel_relaxed(0x3C7097F9, AHB_EN2_REG);
}
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
+ if (soc_class_is_apq8064())
rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
/* Deassert all locally-owned MM AHB resets. */
@@ -6392,7 +6460,7 @@
rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
+ if (soc_class_is_apq8064())
rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
cpu_is_msm8930ab())
@@ -6429,8 +6497,7 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
- || cpu_is_apq8064ab()) {
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064()) {
rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
@@ -6448,7 +6515,7 @@
rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
}
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
rmwreg(0x00000000, TV_CC_REG, 0x00004010);
rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
}
@@ -6459,7 +6526,7 @@
* and wake-up value to max.
*/
rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
}
@@ -6481,8 +6548,7 @@
/* Source the dsi_byte_clks from the DSI PHY PLLs */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
- || cpu_is_apq8064ab())
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064())
rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
@@ -6492,7 +6558,7 @@
* Source the sata_phy_ref_clk from PXO and set predivider of
* sata_pmalive_clk to 1.
*/
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
}
@@ -6501,7 +6567,7 @@
* TODO: Programming below PLLs and prng_clk is temporary and
* needs to be removed after bootloaders program them.
*/
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
u32 is_pll_enabled;
/* Program pxo_src_clk to source from PXO */
@@ -6527,7 +6593,7 @@
writel_relaxed(0x2B, PRNG_CLK_NS_REG);
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
/* Program PLL15 to 975MHz with ref clk = 27MHz */
configure_sr_pll(&pll15_config, &pll15_regs, 0);
} else if (cpu_is_apq8064ab()) {
@@ -6536,6 +6602,9 @@
pll15_config.m = 0x1;
pll15_config.n = 0x3;
configure_sr_pll(&pll15_config, &pll15_regs, 0);
+ } else if (cpu_is_msm8960ab()) {
+ pll3_clk.c.rate = 880000000;
+ configure_sr_pll(&pll3_config, &pll3_regs, 0);
}
/*
@@ -6558,13 +6627,34 @@
}
}
+#define PTE_EFUSE_GFX_PHYS (0x007000BC)
+
+static unsigned long *select_gfx_fmax_plan(unsigned long **gfx_fmax, int size)
+{
+ void __iomem *pte_efuse;
+ u32 gfx_speed_bin;
+
+ pte_efuse = ioremap(PTE_EFUSE_GFX_PHYS, 4);
+ gfx_speed_bin = readl_relaxed(pte_efuse);
+ gfx_speed_bin = (gfx_speed_bin & BM(25, 24)) >> 24;
+ iounmap(pte_efuse);
+
+ if (gfx_speed_bin >= size) {
+ pr_err("GFX_SPEED_BIN: defaulting to 0\n");
+ gfx_speed_bin = 0;
+ }
+
+ pr_info("GFX_SPEED_BIN: %d\n", gfx_speed_bin);
+ return gfx_fmax[gfx_speed_bin];
+}
+
struct clock_init_data msm8960_clock_init_data __initdata;
static void __init msm8960_clock_pre_init(void)
{
/* Initialize clock registers. */
reg_init();
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
+ if (soc_class_is_apq8064())
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
@@ -6583,13 +6673,11 @@
memcpy(msm_clocks_8960, msm_clocks_8960_common,
sizeof(msm_clocks_8960_common));
if (cpu_is_msm8960ab()) {
- pll3_clk.c.rate = 650000000;
- gfx3d_clk.c.fmax[VDD_DIG_LOW] = 192000000;
- gfx3d_clk.c.fmax[VDD_DIG_NOMINAL] = 325000000;
- gfx3d_clk.c.fmax[VDD_DIG_HIGH] = 400000000;
- mdp_clk.freq_tbl = clk_tbl_mdp_8960ab;
- mdp_clk.c.fmax[VDD_DIG_LOW] = 128000000;
- mdp_clk.c.fmax[VDD_DIG_NOMINAL] = 266667000;
+ gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
+ mdp_clk.c.fmax = fmax_mdp_8960ab;
+
+ gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
+ ARRAY_SIZE(fmax_gfx3d_8960ab));
memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
@@ -6608,21 +6696,21 @@
* Change the freq tables for and voltage requirements for
* clocks which differ between chips.
*/
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064aa())
gfx3d_clk.c.fmax = fmax_gfx3d_8064;
- }
- if (cpu_is_apq8064ab()) {
+
+ if (cpu_is_apq8064ab())
gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
- }
+
if ((cpu_is_apq8064() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
- cpu_is_apq8064ab()) {
+ cpu_is_apq8064ab() || cpu_is_apq8064aa()) {
vcodec_clk.c.fmax = fmax_vcodec_8064v2;
ce3_src_clk.c.fmax = fmax_ce3_8064v2;
sdc1_clk.c.fmax = fmax_sdc1_8064v2;
}
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
ijpeg_clk.c.fmax = fmax_ijpeg_8064;
mdp_clk.c.fmax = fmax_mdp_8064;
tv_src_clk.c.fmax = fmax_tv_src_8064;
@@ -6695,7 +6783,7 @@
clk_set_rate(&tsif_ref_clk.c, 105000);
clk_set_rate(&tssc_clk.c, 27000000);
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
}
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index eb16eae..a48bf94 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5174,6 +5174,9 @@
CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "msm_hsic_host"),
CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
CLK_LOOKUP("ref_clk", div_clk2.c, "msm_smsc_hub"),
+ CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_ehci_host"),
+ CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "msm_ehci_host"),
+ CLK_LOOKUP("sleep_clk", gcc_usb2b_phy_sleep_clk.c, "msm_ehci_host"),
CLK_LOOKUP("pwm_clk", div_clk2.c, "0-0048"),
/* Multimedia clocks */
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index c4cbdfd..b5f5a4e 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -93,16 +93,22 @@
#define SDCC2_APPS_CMD_RCGR 0x0510
#define SDCC3_APPS_CMD_RCGR 0x0550
#define BLSP1_QUP1_SPI_APPS_CMD_RCGR 0x064C
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR 0x0660
#define BLSP1_UART1_APPS_CMD_RCGR 0x068C
#define BLSP1_QUP2_SPI_APPS_CMD_RCGR 0x06CC
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR 0x06E0
#define BLSP1_UART2_APPS_CMD_RCGR 0x070C
#define BLSP1_QUP3_SPI_APPS_CMD_RCGR 0x074C
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR 0x0760
#define BLSP1_UART3_APPS_CMD_RCGR 0x078C
#define BLSP1_QUP4_SPI_APPS_CMD_RCGR 0x07CC
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR 0x07E0
#define BLSP1_UART4_APPS_CMD_RCGR 0x080C
#define BLSP1_QUP5_SPI_APPS_CMD_RCGR 0x084C
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR 0x0860
#define BLSP1_UART5_APPS_CMD_RCGR 0x088C
#define BLSP1_QUP6_SPI_APPS_CMD_RCGR 0x08CC
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR 0x08E0
#define BLSP1_UART6_APPS_CMD_RCGR 0x090C
#define PDM2_CMD_RCGR 0x0CD0
#define CE1_CMD_RCGR 0x1050
@@ -523,6 +529,96 @@
},
};
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+ F(19200000, cxo, 1, 0, 0),
+ F(50000000, gpll0, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 50000000),
+ CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 50000000),
+ CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 50000000),
+ CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 50000000),
+ CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 50000000),
+ CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 50000000),
+ CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+ },
+};
+
static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
F( 960000, cxo, 10, 1, 2),
F( 4800000, cxo, 4, 0, 0),
@@ -997,7 +1093,6 @@
static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
- .has_sibling = 1,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
@@ -1021,7 +1116,6 @@
static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
- .has_sibling = 1,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
@@ -1045,7 +1139,6 @@
static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
- .has_sibling = 1,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
@@ -1069,7 +1162,6 @@
static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
- .has_sibling = 1,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
@@ -1093,7 +1185,6 @@
static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
- .has_sibling = 1,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
@@ -1117,7 +1208,6 @@
static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
- .has_sibling = 1,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
@@ -1847,6 +1937,11 @@
{&gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
{&gcc_ce1_clk.c, GCC_BASE, 0x0138},
{&gcc_sys_noc_ipa_axi_clk.c, GCC_BASE, 0x0007},
+ {&gcc_ipa_clk.c, GCC_BASE, 0x01E0},
+ {&gcc_ipa_cnoc_clk.c, GCC_BASE, 0x01E1},
+ {&gcc_ipa_sleep_clk.c, GCC_BASE, 0x01E2},
+ {&gcc_qpic_clk.c, GCC_BASE, 0x01D8},
+ {&gcc_qpic_ahb_clk.c, GCC_BASE, 0x01D9},
{&audio_core_lpaif_pcm_data_oe_clk.c, LPASS_BASE, 0x0030},
{&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
@@ -2049,7 +2144,7 @@
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.spi"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991d000.uart"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
@@ -2062,7 +2157,7 @@
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, "f991d000.uart"),
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
@@ -2431,6 +2526,13 @@
clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&audio_core_slimbus_core_clk_src.c,
audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
+ /*
+ * TODO: set rate on behalf of the i2c driver until the i2c driver
+ * distinguish v1/v2 and call set rate accordingly.
+ */
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2)
+ clk_set_rate(&blsp1_qup3_i2c_apps_clk_src.c,
+ blsp1_qup3_i2c_apps_clk_src.freq_tbl[0].freq_hz);
}
#define GCC_CC_PHYS 0xFC400000
@@ -2445,6 +2547,15 @@
#define APCS_PLL_PHYS 0xF9008018
#define APCS_PLL_SIZE 0x18
+static struct clk *i2c_apps_clks[][2] __initdata = {
+ {&gcc_blsp1_qup1_i2c_apps_clk.c, &blsp1_qup1_i2c_apps_clk_src.c},
+ {&gcc_blsp1_qup2_i2c_apps_clk.c, &blsp1_qup2_i2c_apps_clk_src.c},
+ {&gcc_blsp1_qup3_i2c_apps_clk.c, &blsp1_qup3_i2c_apps_clk_src.c},
+ {&gcc_blsp1_qup4_i2c_apps_clk.c, &blsp1_qup4_i2c_apps_clk_src.c},
+ {&gcc_blsp1_qup5_i2c_apps_clk.c, &blsp1_qup5_i2c_apps_clk_src.c},
+ {&gcc_blsp1_qup6_i2c_apps_clk.c, &blsp1_qup6_i2c_apps_clk_src.c},
+};
+
static void __init msm9625_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -2463,6 +2574,13 @@
if (!virt_bases[APCS_PLL_BASE])
panic("clock-9625: Unable to ioremap APCS_PLL memory!");
+ /* The parent of each of the QUP I2C APPS clocks is an RCG on v2 */
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+ int i, num_cores = ARRAY_SIZE(i2c_apps_clks);
+ for (i = 0; i < num_cores; i++)
+ i2c_apps_clks[i][0]->parent = i2c_apps_clks[i][1];
+ }
+
clk_ops_local_pll.enable = sr_pll_clk_enable_9625;
vdd_dig_reg = regulator_get(NULL, "vdd_dig");
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 4432795..a173ba9 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -598,20 +598,21 @@
static enum handoff branch_clk_handoff(struct clk *c)
{
struct branch_clk *br = to_branch_clk(c);
- return branch_handoff(&br->b, &br->c);
+ if (branch_handoff(&br->b, &br->c) == HANDOFF_ENABLED_CLK) {
+ br->enabled = true;
+ return HANDOFF_ENABLED_CLK;
+ }
+
+ return HANDOFF_DISABLED_CLK;
}
-static enum handoff rcg_clk_handoff(struct clk *c)
+static struct clk *rcg_clk_get_parent(struct clk *c)
{
struct rcg_clk *rcg = to_rcg_clk(c);
uint32_t ctl_val, ns_val, md_val, ns_mask;
struct clk_freq_tbl *freq;
- enum handoff ret;
ctl_val = readl_relaxed(rcg->b.ctl_reg);
- ret = branch_handoff(&rcg->b, &rcg->c);
- if (ret == HANDOFF_DISABLED_CLK)
- return HANDOFF_DISABLED_CLK;
if (rcg->bank_info) {
const struct bank_masks *bank_masks = rcg->bank_info;
@@ -628,21 +629,40 @@
ns_mask = rcg->ns_mask;
md_val = rcg->md_reg ? readl_relaxed(rcg->md_reg) : 0;
}
+
if (!ns_mask)
- return HANDOFF_UNKNOWN_RATE;
+ return NULL;
+
ns_val = readl_relaxed(rcg->ns_reg) & ns_mask;
for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
if ((freq->ns_val & ns_mask) == ns_val &&
(!freq->md_val || freq->md_val == md_val))
break;
}
+
if (freq->freq_hz == FREQ_END)
- return HANDOFF_UNKNOWN_RATE;
+ return NULL;
+ /* Cache the results for the handoff code. */
rcg->current_freq = freq;
- c->parent = freq->src_clk;
- c->rate = freq->freq_hz;
+ return freq->src_clk;
+}
+
+static enum handoff rcg_clk_handoff(struct clk *c)
+{
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ enum handoff ret;
+
+ if (rcg->current_freq && rcg->current_freq->freq_hz != FREQ_END)
+ c->rate = rcg->current_freq->freq_hz;
+
+ ret = branch_handoff(&rcg->b, &rcg->c);
+ if (ret == HANDOFF_DISABLED_CLK)
+ return HANDOFF_DISABLED_CLK;
+
+ rcg->prepared = true;
+ rcg->enabled = true;
return HANDOFF_ENABLED_CLK;
}
@@ -861,6 +881,7 @@
.round_rate = rcg_clk_round_rate,
.reset = rcg_clk_reset,
.set_flags = rcg_clk_set_flags,
+ .get_parent = rcg_clk_get_parent,
};
static int cdiv_clk_enable(struct clk *c)
@@ -940,6 +961,7 @@
reg_val >>= cdiv->div_offset;
cdiv->cur_div = (reg_val & (cdiv->max_div - 1)) + 1;
}
+ c->rate = cdiv->cur_div;
return HANDOFF_ENABLED_CLK;
}
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index cf42355..dd78557 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -69,8 +69,8 @@
#define MND_MODE_MASK BM(13, 12)
#define MND_DUAL_EDGE_MODE_BVAL BVAL(13, 12, 0x2)
#define CMD_RCGR_CONFIG_DIRTY_MASK BM(7, 4)
-#define CBCR_BRANCH_CDIV_MASK BM(24, 16)
-#define CBCR_BRANCH_CDIV_MASKED(val) BVAL(24, 16, (val));
+#define CBCR_CDIV_LSB 16
+#define CBCR_CDIV_MSB 24
enum branch_state {
BRANCH_ON,
@@ -235,21 +235,17 @@
return (rcg->freq_tbl + n)->freq_hz;
}
-static enum handoff _rcg_clk_handoff(struct rcg_clk *rcg, int has_mnd)
+static struct clk *_rcg_clk_get_parent(struct rcg_clk *rcg, int has_mnd)
{
u32 n_regval = 0, m_regval = 0, d_regval = 0;
u32 cfg_regval;
struct clk_freq_tbl *freq;
u32 cmd_rcgr_regval;
- /* Is the root enabled? */
- cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
- if ((cmd_rcgr_regval & CMD_RCGR_ROOT_STATUS_BIT))
- return HANDOFF_DISABLED_CLK;
-
/* Is there a pending configuration? */
+ cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
- return HANDOFF_UNKNOWN_RATE;
+ return NULL;
/* Get values of m, n, d, div and src_sel registers. */
if (has_mnd) {
@@ -299,23 +295,45 @@
/* No known frequency found */
if (freq->freq_hz == FREQ_END)
- return HANDOFF_UNKNOWN_RATE;
+ return NULL;
rcg->current_freq = freq;
- rcg->c.parent = freq->src_clk;
- rcg->c.rate = freq->freq_hz;
+ return freq->src_clk;
+}
+
+static enum handoff _rcg_clk_handoff(struct rcg_clk *rcg)
+{
+ u32 cmd_rcgr_regval;
+
+ if (rcg->current_freq && rcg->current_freq->freq_hz != FREQ_END)
+ rcg->c.rate = rcg->current_freq->freq_hz;
+
+ /* Is the root enabled? */
+ cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+ if ((cmd_rcgr_regval & CMD_RCGR_ROOT_STATUS_BIT))
+ return HANDOFF_DISABLED_CLK;
return HANDOFF_ENABLED_CLK;
}
+static struct clk *rcg_mnd_clk_get_parent(struct clk *c)
+{
+ return _rcg_clk_get_parent(to_rcg_clk(c), 1);
+}
+
+static struct clk *rcg_clk_get_parent(struct clk *c)
+{
+ return _rcg_clk_get_parent(to_rcg_clk(c), 0);
+}
+
static enum handoff rcg_mnd_clk_handoff(struct clk *c)
{
- return _rcg_clk_handoff(to_rcg_clk(c), 1);
+ return _rcg_clk_handoff(to_rcg_clk(c));
}
static enum handoff rcg_clk_handoff(struct clk *c)
{
- return _rcg_clk_handoff(to_rcg_clk(c), 0);
+ return _rcg_clk_handoff(to_rcg_clk(c));
}
#define BRANCH_CHECK_MASK BM(31, 28)
@@ -412,8 +430,8 @@
spin_lock_irqsave(&local_clock_reg_lock, flags);
regval = readl_relaxed(CBCR_REG(branch));
- regval &= ~CBCR_BRANCH_CDIV_MASK;
- regval |= CBCR_BRANCH_CDIV_MASKED(rate);
+ regval &= ~BM(CBCR_CDIV_MSB, CBCR_CDIV_LSB);
+ regval |= BVAL(CBCR_CDIV_MSB, CBCR_CDIV_LSB, rate);
writel_relaxed(regval, CBCR_REG(branch));
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
@@ -496,9 +514,12 @@
if ((cbcr_regval & CBCR_BRANCH_OFF_BIT))
return HANDOFF_DISABLED_CLK;
- if (c->parent) {
- if (c->parent->ops->handoff)
- return c->parent->ops->handoff(c->parent);
+ if (branch->max_div) {
+ cbcr_regval &= BM(CBCR_CDIV_MSB, CBCR_CDIV_LSB);
+ cbcr_regval >>= CBCR_CDIV_LSB;
+ c->rate = cbcr_regval;
+ } else if (!branch->has_sibling) {
+ c->rate = clk_get_rate(c->parent);
}
return HANDOFF_ENABLED_CLK;
@@ -611,6 +632,7 @@
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
.handoff = rcg_clk_handoff,
+ .get_parent = rcg_clk_get_parent,
};
struct clk_ops clk_ops_rcg_mnd = {
@@ -619,6 +641,7 @@
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
.handoff = rcg_mnd_clk_handoff,
+ .get_parent = rcg_mnd_clk_get_parent,
};
struct clk_ops clk_ops_branch = {
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 79bc639..aca6494 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -348,6 +348,16 @@
return ret;
}
+static enum handoff mdss_dsi_pll_handoff(struct clk *c)
+{
+ /*
+ * FIXME: Continuous display is not implemented. So the display is
+ * always off. Implement a poor man's handoff by always returning
+ * "disabled".
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
void hdmi_pll_disable(void)
{
clk_enable(mdss_dsi_ahb_clk);
@@ -766,6 +776,7 @@
.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_handoff,
};
struct clk_ops clk_ops_dsi_byte_pll = {
@@ -773,4 +784,5 @@
.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_handoff,
};
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index a4def28..c1cc27b 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -285,6 +285,18 @@
if (rc < 0)
return HANDOFF_DISABLED_CLK;
+ /*
+ * Since RPM handoff code may update the software rate of the clock by
+ * querying the RPM, we need to make sure our request to RPM now
+ * matches the software rate of the clock. When we send the request
+ * to RPM, we also need to update any other state info we would
+ * normally update. So, call the appropriate clock function instead
+ * of directly using the RPM driver APIs.
+ */
+ rc = rpm_clk_prepare(clk);
+ if (rc < 0)
+ return HANDOFF_DISABLED_CLK;
+
return HANDOFF_ENABLED_CLK;
}
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 7421ba6..c3145ef 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2010-2011, Code Aurora Forum. 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
@@ -139,11 +138,17 @@
static enum handoff voter_clk_handoff(struct clk *clk)
{
- /* Apply default rate vote */
- if (clk->rate)
- return HANDOFF_ENABLED_CLK;
+ if (!clk->rate)
+ return HANDOFF_DISABLED_CLK;
- return HANDOFF_DISABLED_CLK;
+ /*
+ * Send the default rate to the parent if necessary and update the
+ * software state of the voter clock.
+ */
+ if (voter_clk_prepare(clk) < 0)
+ return HANDOFF_DISABLED_CLK;
+
+ return HANDOFF_ENABLED_CLK;
}
struct clk_ops clk_ops_voter = {
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index c2bf5ba..e0ee084 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/clock.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-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
@@ -467,56 +467,83 @@
}
EXPORT_SYMBOL(msm_clock_register);
-static enum handoff __init __handoff_clk(struct clk *clk)
+static int __init __handoff_clk(struct clk *clk)
{
- enum handoff ret;
- struct handoff_clk *h;
- unsigned long rate;
- int err = 0;
+ enum handoff state = HANDOFF_DISABLED_CLK;
+ struct handoff_clk *h = NULL;
+ int rc;
+
+ if (clk == NULL || clk->flags & CLKFLAG_INIT_DONE ||
+ clk->flags & CLKFLAG_SKIP_HANDOFF)
+ return 0;
+
+ if (clk->flags & CLKFLAG_INIT_ERR)
+ return -ENXIO;
+
+ /* Handoff any 'depends' clock first. */
+ rc = __handoff_clk(clk->depends);
+ if (rc)
+ goto err;
/*
- * Tree roots don't have parents, but need to be handed off. So,
- * terminate recursion by returning "enabled". Also return "enabled"
- * for clocks with non-zero enable counts since they must have already
- * been handed off.
+ * Handoff functions for the parent must be called before the
+ * children can be handed off. Without handing off the parents and
+ * knowing their rate and state (on/off), it's impossible to figure
+ * out the rate and state of the children.
*/
- if (clk == NULL || clk->count)
- return HANDOFF_ENABLED_CLK;
+ if (clk->ops->get_parent)
+ clk->parent = clk->ops->get_parent(clk);
- /* Clocks without handoff functions are assumed to be disabled. */
- if (!clk->ops->handoff || (clk->flags & CLKFLAG_SKIP_HANDOFF))
- return HANDOFF_DISABLED_CLK;
+ if (IS_ERR(clk->parent)) {
+ rc = PTR_ERR(clk->parent);
+ goto err;
+ }
- /*
- * Handoff functions for children must be called before their parents'
- * so that the correct parent is available below.
- */
- ret = clk->ops->handoff(clk);
- if (ret == HANDOFF_ENABLED_CLK) {
- ret = __handoff_clk(clk->parent);
- if (ret == HANDOFF_ENABLED_CLK) {
- h = kmalloc(sizeof(*h), GFP_KERNEL);
- if (!h) {
- err = -ENOMEM;
- goto out;
- }
- err = clk_prepare_enable(clk);
- if (err)
- goto out;
- rate = clk_get_rate(clk);
- if (rate)
- pr_debug("%s rate=%lu\n", clk->dbg_name, rate);
- h->clk = clk;
- list_add_tail(&h->list, &handoff_list);
+ rc = __handoff_clk(clk->parent);
+ if (rc)
+ goto err;
+
+ if (clk->ops->handoff)
+ state = clk->ops->handoff(clk);
+
+ if (state == HANDOFF_ENABLED_CLK) {
+
+ h = kmalloc(sizeof(*h), GFP_KERNEL);
+ if (!h) {
+ rc = -ENOMEM;
+ goto err;
}
+
+ rc = clk_prepare_enable(clk->parent);
+ if (rc)
+ goto err;
+
+ rc = clk_prepare_enable(clk->depends);
+ if (rc)
+ goto err_depends;
+
+ rc = vote_rate_vdd(clk, clk->rate);
+ WARN(rc, "%s unable to vote for voltage!\n", clk->dbg_name);
+
+ clk->count = 1;
+ clk->prepare_count = 1;
+ h->clk = clk;
+ list_add_tail(&h->list, &handoff_list);
+
+ pr_debug("Handed off %s rate=%lu\n", clk->dbg_name, clk->rate);
}
-out:
- if (err) {
- pr_err("%s handoff failed (%d)\n", clk->dbg_name, err);
- kfree(h);
- ret = HANDOFF_DISABLED_CLK;
- }
- return ret;
+
+ clk->flags |= CLKFLAG_INIT_DONE;
+
+ return 0;
+
+err_depends:
+ clk_disable_unprepare(clk->parent);
+err:
+ kfree(h);
+ clk->flags |= CLKFLAG_INIT_ERR;
+ pr_err("%s handoff failed (%d)\n", clk->dbg_name, rc);
+ return rc;
}
/**
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index dd2dc1d..056f19e 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -80,8 +80,7 @@
cpu_pm_enter();
#endif
- pm_mode = msm_pm_idle_prepare(dev, drv, index);
- dev->last_residency = msm_pm_idle_enter(pm_mode);
+ pm_mode = msm_pm_idle_enter(dev, drv, index);
for (i = 0; i < dev->state_count; i++) {
st_usage = &dev->states_usage[i];
if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index c986064..f87c540 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -24,6 +24,7 @@
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <mach/usbdiag.h>
+#include <mach/msm_serial_hs_lite.h>
#include <mach/msm_sps.h>
#include <mach/dma.h>
#include <mach/msm_dsps.h>
@@ -51,6 +52,7 @@
/* Address of GSBI blocks */
#define MSM_GSBI1_PHYS 0x12440000
+#define MSM_GSBI2_PHYS 0x12480000
#define MSM_GSBI3_PHYS 0x16200000
#define MSM_GSBI4_PHYS 0x16300000
#define MSM_GSBI5_PHYS 0x1A200000
@@ -59,7 +61,9 @@
/* GSBI UART devices */
#define MSM_UART1DM_PHYS (MSM_GSBI1_PHYS + 0x10000)
+#define MSM_UART2DM_PHYS (MSM_GSBI2_PHYS + 0x10000)
#define MSM_UART3DM_PHYS (MSM_GSBI3_PHYS + 0x40000)
+#define MSM_UART4DM_PHYS (MSM_GSBI4_PHYS + 0x40000)
#define MSM_UART5DM_PHYS (MSM_GSBI5_PHYS + 0x40000)
#define MSM_UART6DM_PHYS (MSM_GSBI6_PHYS + 0x40000)
#define MSM_UART7DM_PHYS (MSM_GSBI7_PHYS + 0x40000)
@@ -203,6 +207,38 @@
.resource = resources_uart_gsbi1,
};
+static struct resource resources_uart_gsbi2[] = {
+ {
+ .start = APQ8064_GSBI2_UARTDM_IRQ,
+ .end = APQ8064_GSBI2_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART2DM_PHYS,
+ .end = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_GSBI2_PHYS,
+ .end = MSM_GSBI2_PHYS + PAGE_SIZE - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct msm_serial_hslite_platform_data uart_gsbi2_pdata = {
+ .line = 0,
+};
+
+struct platform_device apq8064_device_uart_gsbi2 = {
+ .name = "msm_serial_hsl",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(resources_uart_gsbi2),
+ .resource = resources_uart_gsbi2,
+ .dev.platform_data = &uart_gsbi2_pdata,
+};
+
static struct resource resources_uart_gsbi3[] = {
{
.start = GSBI3_UARTDM_IRQ,
@@ -350,6 +386,38 @@
.resource = resources_qup_i2c_gsbi4,
};
+static struct resource resources_uart_gsbi4[] = {
+ {
+ .start = GSBI4_UARTDM_IRQ,
+ .end = GSBI4_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART4DM_PHYS,
+ .end = MSM_UART4DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_GSBI4_PHYS,
+ .end = MSM_GSBI4_PHYS + PAGE_SIZE - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct msm_serial_hslite_platform_data uart_gsbi4_pdata = {
+ .line = 2,
+};
+
+struct platform_device apq8064_device_uart_gsbi4 = {
+ .name = "msm_serial_hsl",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(resources_uart_gsbi4),
+ .resource = resources_uart_gsbi4,
+ .dev.platform_data = &uart_gsbi4_pdata,
+};
+
static struct resource resources_qup_spi_gsbi5[] = {
{
.name = "spi_base",
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8762aa1..446f3f2 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -2459,11 +2459,6 @@
.id = -1,
};
-struct platform_device msm_fm_loopback = {
- .name = "msm-pcm-loopback",
- .id = -1,
-};
-
static struct fs_driver_data gfx2d0_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 15994565..ee6c5cb 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1546,7 +1546,7 @@
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm9615_io();
l2x0_cache_init();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index c8b160c..907af68 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -2147,7 +2147,7 @@
void __init msm_common_io_init(void)
{
msm_map_common_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
msm7x27x_cache_init();
}
@@ -2163,7 +2163,7 @@
{
msm_map_msm8625_io();
- if (IS_ERR_OR_NULL(socinfo_init()))
+ if (socinfo_init() < 0)
pr_err("socinfo_init() failed!\n");
msm7x27x_cache_init();
}
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 3471a30..8301c29 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/devices.h
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2012, 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
@@ -85,7 +85,9 @@
extern struct platform_device msm8960_device_ebi1_ch1_erp;
extern struct platform_device apq8064_device_uart_gsbi1;
+extern struct platform_device apq8064_device_uart_gsbi2;
extern struct platform_device apq8064_device_uart_gsbi3;
+extern struct platform_device apq8064_device_uart_gsbi4;
extern struct platform_device apq8064_device_uart_gsbi7;
extern struct platform_device apq8064_device_qup_i2c_gsbi1;
extern struct platform_device apq8064_device_qup_i2c_gsbi3;
@@ -253,7 +255,6 @@
extern struct platform_device msm_i2s_cpudai4;
extern struct platform_device msm_i2s_cpudai5;
extern struct platform_device msm_cpudai_stub;
-extern struct platform_device msm_fm_loopback;
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 0f2feaa..475b483 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-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
@@ -69,7 +69,6 @@
enum handoff {
HANDOFF_ENABLED_CLK,
HANDOFF_DISABLED_CLK,
- HANDOFF_UNKNOWN_RATE,
};
struct clk_ops {
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index d69b372..1191bb7 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009, 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
@@ -21,6 +21,8 @@
#define CLKFLAG_SKIP_HANDOFF 0x00000100
#define CLKFLAG_MIN 0x00000400
#define CLKFLAG_MAX 0x00000800
+#define CLKFLAG_INIT_DONE 0x00001000
+#define CLKFLAG_INIT_ERR 0x00002000
struct clk_lookup;
struct clk;
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 137d243..2d47e4e 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -16,7 +16,7 @@
#ifndef __ASM_ARCH_MSM_GPIO_H
#define __ASM_ARCH_MSM_GPIO_H
-#define ARCH_NR_GPIOS 512
+#define ARCH_NR_GPIOS 1024
#include <linux/interrupt.h>
#include <asm-generic/gpio.h>
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index fd63fd2..46069d2 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -24,6 +24,7 @@
struct mdm_platform_data {
char *mdm_version;
int ramdump_delay_ms;
+ int ps_hold_delay_ms;
int soft_reset_inverted;
int early_power_on;
int sfr_query;
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
index ab43a8a..81b3c48 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8226.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 software is licensed under the terms of the GNU General Public
@@ -37,9 +37,6 @@
#define MSM8226_TLMM_PHYS 0xFD510000
#define MSM8226_TLMM_SIZE SZ_16K
-#define MSM8226_IMEM_PHYS 0xFE805000
-#define MSM8226_IMEM_SIZE SZ_4K
-
#define MSM8226_MPM2_PSHOLD_PHYS 0xFC4AB000
#define MSM8226_MPM2_PSHOLD_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 05544af..b07ddba 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -30,9 +30,6 @@
#define MSM8610_TLMM_PHYS 0xFD510000
#define MSM8610_TLMM_SIZE SZ_16K
-#define MSM8610_IMEM_PHYS 0xFE805000
-#define MSM8610_IMEM_SIZE SZ_4K
-
#define MSM8610_MPM2_PSHOLD_PHYS 0xFC4AB000
#define MSM8610_MPM2_PSHOLD_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
index 15be294..0d8f371 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -40,15 +40,6 @@
#define MSM8974_MPM2_PSHOLD_PHYS 0xFC4AB000
#define MSM8974_MPM2_PSHOLD_SIZE SZ_4K
-/*
- * TODO: Revert IMEM_PHYS back to actual
- * address 0xfe805000
- * after IMEM issues resolved.
- *
- */
-#define MSM8974_IMEM_PHYS 0xFC42B000
-#define MSM8974_IMEM_SIZE SZ_4K
-
#ifdef CONFIG_DEBUG_MSM8974_UART
#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
#define MSM_DEBUG_UART_PHYS 0xF991E000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
index 89252a5..54edb82 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. 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
@@ -40,15 +40,6 @@
#define MSM9625_TLMM_PHYS 0xFD510000
#define MSM9625_TLMM_SIZE SZ_16K
-/*
- * TODO: Revert IMEM_PHYS back to actual
- * address 0xfe807800
- * after IMEM issues resolved.
- *
- */
-#define MSM9625_IMEM_PHYS 0xFC42B000
-#define MSM9625_IMEM_SIZE SZ_2K
-
#define MSM9625_MPM2_PSHOLD_PHYS 0xFC4AB000
#define MSM9625_MPM2_PSHOLD_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index e88c4df..9a031b2 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -199,10 +199,13 @@
SMEM_SSR_REASON_DSPS0,
SMEM_SSR_REASON_VCODEC0,
SMEM_SMP2P_APPS_BASE = 427,
- SMEM_SMP2P_MODEM_BASE = 435,
- SMEM_SMP2P_AUDIO_BASE = 443,
- SMEM_SMP2P_WIRLESS_BASE = 451,
- SMEM_SMP2P_POWER_BASE = 459,
+ SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8, /* 435 */
+ SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8, /* 443 */
+ SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
+ SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
+ SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8, /* 467 */
+ SMEM_BAM_PIPE_MEMORY, /* 468 */
+ SMEM_IMAGE_VERSION_TABLE, /* 469 */
SMEM_NUM_ITEMS,
};
diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h
index 72e7337..8c8b821 100644
--- a/arch/arm/mach-msm/include/mach/remote_spinlock.h
+++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h
@@ -39,233 +39,15 @@
typedef raw_remote_spinlock_t *_remote_spinlock_t;
#define remote_spinlock_id_t const char *
-#define SPINLOCK_PID_APPS 1
-
-static inline void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
-{
- unsigned long tmp;
-
- __asm__ __volatile__(
-"1: ldrex %0, [%1]\n"
-" teq %0, #0\n"
-" strexeq %0, %2, [%1]\n"
-" teqeq %0, #0\n"
-" bne 1b"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (SPINLOCK_PID_APPS)
- : "cc");
-
- smp_mb();
-}
-
-static inline int __raw_remote_ex_spin_trylock(raw_remote_spinlock_t *lock)
-{
- unsigned long tmp;
-
- __asm__ __volatile__(
-" ldrex %0, [%1]\n"
-" teq %0, #0\n"
-" strexeq %0, %2, [%1]\n"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (SPINLOCK_PID_APPS)
- : "cc");
-
- if (tmp == 0) {
- smp_mb();
- return 1;
- }
- return 0;
-}
-
-static inline void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock)
-{
- int lock_owner;
-
- smp_mb();
- lock_owner = readl_relaxed(&lock->lock);
- if (lock_owner != SPINLOCK_PID_APPS) {
- pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
- __func__, lock_owner);
- }
-
- __asm__ __volatile__(
-" str %1, [%0]\n"
- :
- : "r" (&lock->lock), "r" (0)
- : "cc");
-}
-
-static inline void __raw_remote_swp_spin_lock(raw_remote_spinlock_t *lock)
-{
- unsigned long tmp;
-
- __asm__ __volatile__(
-"1: swp %0, %2, [%1]\n"
-" teq %0, #0\n"
-" bne 1b"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
- : "cc");
-
- smp_mb();
-}
-
-static inline int __raw_remote_swp_spin_trylock(raw_remote_spinlock_t *lock)
-{
- unsigned long tmp;
-
- __asm__ __volatile__(
-" swp %0, %2, [%1]\n"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
- : "cc");
-
- if (tmp == 0) {
- smp_mb();
- return 1;
- }
- return 0;
-}
-
-static inline void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock)
-{
- int lock_owner;
-
- smp_mb();
- lock_owner = readl_relaxed(&lock->lock);
- if (lock_owner != SPINLOCK_PID_APPS) {
- pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
- __func__, lock_owner);
- }
-
- __asm__ __volatile__(
-" str %1, [%0]"
- :
- : "r" (&lock->lock), "r" (0)
- : "cc");
-}
-
-#define DEK_LOCK_REQUEST 1
-#define DEK_LOCK_YIELD (!DEK_LOCK_REQUEST)
-#define DEK_YIELD_TURN_SELF 0
-static inline void __raw_remote_dek_spin_lock(raw_remote_spinlock_t *lock)
-{
- lock->dek.self_lock = DEK_LOCK_REQUEST;
-
- while (lock->dek.other_lock) {
-
- if (lock->dek.next_yield == DEK_YIELD_TURN_SELF)
- lock->dek.self_lock = DEK_LOCK_YIELD;
-
- while (lock->dek.other_lock)
- ;
-
- lock->dek.self_lock = DEK_LOCK_REQUEST;
- }
- lock->dek.next_yield = DEK_YIELD_TURN_SELF;
-
- smp_mb();
-}
-
-static inline int __raw_remote_dek_spin_trylock(raw_remote_spinlock_t *lock)
-{
- lock->dek.self_lock = DEK_LOCK_REQUEST;
-
- if (lock->dek.other_lock) {
- lock->dek.self_lock = DEK_LOCK_YIELD;
- return 0;
- }
-
- lock->dek.next_yield = DEK_YIELD_TURN_SELF;
-
- smp_mb();
- return 1;
-}
-
-static inline void __raw_remote_dek_spin_unlock(raw_remote_spinlock_t *lock)
-{
- smp_mb();
-
- lock->dek.self_lock = DEK_LOCK_YIELD;
-}
-
-static inline int __raw_remote_dek_spin_release(raw_remote_spinlock_t *lock,
- uint32_t pid)
-{
- return -EPERM;
-}
-
-static inline int __raw_remote_dek_spin_owner(raw_remote_spinlock_t *lock)
-{
- return -EPERM;
-}
-
-static inline void __raw_remote_sfpb_spin_lock(raw_remote_spinlock_t *lock)
-{
- do {
- writel_relaxed(SPINLOCK_PID_APPS, lock);
- smp_mb();
- } while (readl_relaxed(lock) != SPINLOCK_PID_APPS);
-}
-
-static inline int __raw_remote_sfpb_spin_trylock(raw_remote_spinlock_t *lock)
-{
- return 1;
-}
-
-static inline void __raw_remote_sfpb_spin_unlock(raw_remote_spinlock_t *lock)
-{
- int lock_owner;
-
- lock_owner = readl_relaxed(lock);
- if (lock_owner != SPINLOCK_PID_APPS) {
- pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
- __func__, lock_owner);
- }
-
- writel_relaxed(0, lock);
- smp_mb();
-}
-
-/**
- * Release spinlock if it is owned by @pid.
- *
- * This is only to be used for situations where the processor owning
- * the spinlock has crashed and the spinlock must be released.
- *
- * @lock: lock structure
- * @pid: processor ID of processor to release
- */
-static inline int __raw_remote_gen_spin_release(raw_remote_spinlock_t *lock,
- uint32_t pid)
-{
- int ret = 1;
-
- if (readl_relaxed(&lock->lock) == pid) {
- writel_relaxed(0, &lock->lock);
- wmb();
- ret = 0;
- }
- return ret;
-}
-
-/**
- * Return owner of the spinlock.
- *
- * @lock: pointer to lock structure
- * @returns: >= 0 owned PID; < 0 for error case
- *
- * Used for testing. PID's are assumed to be 31 bits or less.
- */
-static inline int __raw_remote_gen_spin_owner(raw_remote_spinlock_t *lock)
-{
- rmb();
- return readl_relaxed(&lock->lock);
-}
#if defined(CONFIG_MSM_SMD) || defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
int _remote_spin_lock_init(remote_spinlock_id_t, _remote_spinlock_t *lock);
void _remote_spin_release_all(uint32_t pid);
+void _remote_spin_lock(_remote_spinlock_t *lock);
+void _remote_spin_unlock(_remote_spinlock_t *lock);
+int _remote_spin_trylock(_remote_spinlock_t *lock);
+int _remote_spin_release(_remote_spinlock_t *lock, uint32_t pid);
+int _remote_spin_owner(_remote_spinlock_t *lock);
#else
static inline
int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
@@ -273,42 +55,22 @@
return -EINVAL;
}
static inline void _remote_spin_release_all(uint32_t pid) {}
+static inline void _remote_spin_lock(_remote_spinlock_t *lock) {}
+static inline void _remote_spin_unlock(_remote_spinlock_t *lock) {}
+static inline int _remote_spin_trylock(_remote_spinlock_t *lock)
+{
+ return -ENODEV;
+}
+static inline int _remote_spin_release(_remote_spinlock_t *lock, uint32_t pid)
+{
+ return -ENODEV;
+}
+static inline int _remote_spin_owner(_remote_spinlock_t *lock)
+{
+ return -ENODEV;
+}
#endif
-#if defined(CONFIG_MSM_REMOTE_SPINLOCK_DEKKERS)
-/* Use Dekker's algorithm when LDREX/STREX and SWP are unavailable for
- * shared memory */
-#define _remote_spin_lock(lock) __raw_remote_dek_spin_lock(*lock)
-#define _remote_spin_unlock(lock) __raw_remote_dek_spin_unlock(*lock)
-#define _remote_spin_trylock(lock) __raw_remote_dek_spin_trylock(*lock)
-#define _remote_spin_release(lock, pid) __raw_remote_dek_spin_release(*lock,\
- pid)
-#define _remote_spin_owner(lock) __raw_remote_dek_spin_owner(*lock)
-#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SWP)
-/* Use SWP-based locks when LDREX/STREX are unavailable for shared memory. */
-#define _remote_spin_lock(lock) __raw_remote_swp_spin_lock(*lock)
-#define _remote_spin_unlock(lock) __raw_remote_swp_spin_unlock(*lock)
-#define _remote_spin_trylock(lock) __raw_remote_swp_spin_trylock(*lock)
-#define _remote_spin_release(lock, pid) __raw_remote_gen_spin_release(*lock,\
- pid)
-#define _remote_spin_owner(lock) __raw_remote_gen_spin_owner(*lock)
-#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
-/* Use SFPB Hardware Mutex Registers */
-#define _remote_spin_lock(lock) __raw_remote_sfpb_spin_lock(*lock)
-#define _remote_spin_unlock(lock) __raw_remote_sfpb_spin_unlock(*lock)
-#define _remote_spin_trylock(lock) __raw_remote_sfpb_spin_trylock(*lock)
-#define _remote_spin_release(lock, pid) __raw_remote_gen_spin_release(*lock,\
- pid)
-#define _remote_spin_owner(lock) __raw_remote_gen_spin_owner(*lock)
-#else
-/* Use LDREX/STREX for shared memory locking, when available */
-#define _remote_spin_lock(lock) __raw_remote_ex_spin_lock(*lock)
-#define _remote_spin_unlock(lock) __raw_remote_ex_spin_unlock(*lock)
-#define _remote_spin_trylock(lock) __raw_remote_ex_spin_trylock(*lock)
-#define _remote_spin_release(lock, pid) __raw_remote_gen_spin_release(*lock, \
- pid)
-#define _remote_spin_owner(lock) __raw_remote_gen_spin_owner(*lock)
-#endif
/* Remote mutex definitions. */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index b0fe4ba..5b4f00e 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -105,6 +105,7 @@
MSM_CPU_7X25AB,
MSM_CPU_8064,
MSM_CPU_8064AB,
+ MSM_CPU_8064AA,
MSM_CPU_8930,
MSM_CPU_8930AA,
MSM_CPU_8930AB,
@@ -147,7 +148,7 @@
uint32_t socinfo_get_platform_version(void);
enum pmic_model socinfo_get_pmic_model(void);
uint32_t socinfo_get_pmic_die_revision(void);
-struct device * __init socinfo_init(void) __must_check;
+int __init socinfo_init(void) __must_check;
const int read_msm_cpu_type(void);
const int get_core_count(void);
const int cpu_is_krait(void);
@@ -332,6 +333,15 @@
#endif
}
+static inline int cpu_is_apq8064aa(void)
+{
+#ifdef CONFIG_ARCH_APQ8064
+ return read_msm_cpu_type() == MSM_CPU_8064AA;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_msm8930(void)
{
#ifdef CONFIG_ARCH_MSM8930
@@ -473,7 +483,7 @@
static inline int soc_class_is_apq8064(void)
{
- return cpu_is_apq8064() || cpu_is_apq8064ab();
+ return cpu_is_apq8064() || cpu_is_apq8064ab() || cpu_is_apq8064aa();
}
static inline int soc_class_is_msm8930(void)
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index b3fb8af..a7f052e 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -163,6 +163,12 @@
*/
int usb_bam_client_ready(bool ready);
+/**
+ * Returns QDSS BAM connection number
+ *
+ */
+u8 usb_bam_get_qdss_num(void);
+
#else
static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
{
@@ -216,5 +222,10 @@
return -ENODEV;
}
+static inline u8 usb_bam_get_qdss_num(void)
+{
+ return -ENODEV;
+}
+
#endif
#endif /* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 013b4b2..7d13710 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -28,8 +28,10 @@
#include <mach/memory.h>
#include <asm/mach/map.h>
#include <linux/dma-mapping.h>
+#include <linux/of_fdt.h>
#include <mach/board.h>
+#include "board-dt.h"
#define MSM_CHIP_DEVICE(name, chip) { \
.virtual = (unsigned long) MSM_##name##_BASE, \
@@ -303,7 +305,6 @@
MSM_CHIP_DEVICE(APCS_GCC, MSM8974),
MSM_CHIP_DEVICE(TLMM, MSM8974),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8974),
- MSM_CHIP_DEVICE(IMEM, MSM8974),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.length = MSM_SHARED_RAM_SIZE,
@@ -319,6 +320,7 @@
{
msm_shared_ram_phys = MSM8974_MSM_SHARED_RAM_PHYS;
msm_map_io(msm_8974_io_desc, ARRAY_SIZE(msm_8974_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MSM8974 */
@@ -470,7 +472,6 @@
MSM_CHIP_DEVICE(TLMM, MSM9625),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM9625),
MSM_CHIP_DEVICE(TMR, MSM9625),
- MSM_CHIP_DEVICE(IMEM, MSM9625),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.length = MSM_SHARED_RAM_SIZE,
@@ -486,6 +487,7 @@
{
msm_shared_ram_phys = MSM9625_SHARED_RAM_PHYS;
msm_map_io(msm9625_io_desc, ARRAY_SIZE(msm9625_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MSM9625 */
@@ -518,7 +520,6 @@
MSM_CHIP_DEVICE(QGIC_CPU, MSM8226),
MSM_CHIP_DEVICE(APCS_GCC, MSM8226),
MSM_CHIP_DEVICE(TLMM, MSM8226),
- MSM_CHIP_DEVICE(IMEM, MSM8226),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8226),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
@@ -535,6 +536,7 @@
{
msm_shared_ram_phys = MSM8226_MSM_SHARED_RAM_PHYS;
msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MSM8226 */
@@ -543,7 +545,6 @@
MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
MSM_CHIP_DEVICE(TLMM, MSM8610),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
- MSM_CHIP_DEVICE(IMEM, MSM8610),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.length = MSM_SHARED_RAM_SIZE,
@@ -555,5 +556,6 @@
{
msm_shared_ram_phys = MSM8610_MSM_SHARED_RAM_PHYS;
msm_map_io(msm8610_io_desc, ARRAY_SIZE(msm8610_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MSM8610 */
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 8c0bf4b..5d1b5e4 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -40,7 +40,7 @@
#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
-#define NUM_SMD_XPRTS 3
+#define NUM_SMD_XPRTS 4
#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
struct msm_ipc_router_smd_xprt {
@@ -76,6 +76,7 @@
{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
+ {"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
};
static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index dd61db3..aa03a6a 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -27,28 +27,28 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/krait-regulator.h>
+#include <linux/debugfs.h>
#include <mach/msm_iomap.h>
#include "spm.h"
+#include "pm.h"
/*
* supply
* from
* pmic
* gang
- * | LDO BYP [6]
- * | /
- * | /
- * |_______/ _____
- * | |
- * ___|___ |
- * | | |
- * | | /
- * | LDO | /
- * | | / BHS[6]
- * |_______| |
- * | |
- * |________________|
+ * |
+ * |________________________________
+ * | | |
+ * ___|___ | |
+ * | | | |
+ * | | / /
+ * | LDO | / /LDO BYP [6]
+ * | | / BHS[6] /(bypass is a weak BHS
+ * |_______| | | needs to be on when in
+ * | | | BHS mode)
+ * |________________|_______________|
* |
* ________|________
* | |
@@ -88,6 +88,10 @@
#define PWR_GATE_CONFIG 0x00000044
#define VERSION 0x00000FD0
+/* MDD register group */
+#define MDD_CONFIG_CTL 0x00000000
+#define MDD_MODE 0x00000010
+
/* bit definitions for APC_PWR_GATE_CTL */
#define BHS_CNT_BIT_POS 24
#define BHS_CNT_MASK KRAIT_MASK(31, 24)
@@ -117,6 +121,18 @@
#define VREF_LDO_BIT_POS 0
#define VREF_LDO_MASK KRAIT_MASK(6, 0)
+#define LDO_HDROOM_MIN 50000
+#define LDO_HDROOM_MAX 250000
+
+#define LDO_UV_MIN 465000
+#define LDO_UV_MAX 750000
+
+#define LDO_TH_MIN 600000
+#define LDO_TH_MAX 900000
+
+#define LDO_DELTA_MIN 10000
+#define LDO_DELTA_MAX 100000
+
/**
* struct pmic_gang_vreg -
* @name: the string used to represent the gang
@@ -136,6 +152,8 @@
struct list_head krait_power_vregs;
struct mutex krait_power_vregs_lock;
bool pfm_mode;
+ int pmic_min_uV_for_retention;
+ bool retention_enabled;
};
static struct pmic_gang_vreg *the_gang;
@@ -155,15 +173,26 @@
int load_uA;
enum krait_supply_mode mode;
void __iomem *reg_base;
+ void __iomem *mdd_base;
int ldo_default_uV;
int retention_uV;
int headroom_uV;
int ldo_threshold_uV;
+ int ldo_delta_uV;
bool online;
};
static u32 version;
+static int is_between(int left, int right, int value)
+{
+ if (left >= right && left >= value && value >= right)
+ return 1;
+ if (left <= right && left <= value && value <= right)
+ return 1;
+ return 0;
+}
+
static void krait_masked_write(struct krait_power_vreg *kvreg,
int reg, uint32_t mask, uint32_t val)
{
@@ -182,6 +211,23 @@
mb();
}
+static int get_krait_retention_ldo_uv(struct krait_power_vreg *kvreg)
+{
+ uint32_t reg_val;
+ int uV;
+
+ reg_val = readl_relaxed(kvreg->reg_base + APC_LDO_VREF_SET);
+ reg_val &= VREF_RET_MASK;
+ reg_val >>= VREF_RET_POS;
+
+ if (reg_val == 0)
+ uV = 0;
+ else
+ uV = KRAIT_LDO_VOLTAGE_OFFSET + reg_val * KRAIT_LDO_STEP;
+
+ return uV;
+}
+
static int get_krait_ldo_uv(struct krait_power_vreg *kvreg)
{
uint32_t reg_val;
@@ -225,15 +271,13 @@
{
if (kvreg->mode == HS_MODE)
return 0;
-
- /*
- * enable ldo bypass - the krait is powered still by LDO since
- * LDO is enabled and BHS is disabled
- */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
-
/* enable bhs */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+ BHS_SEG_EN_MASK | BHS_EN_MASK,
+ BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS | BHS_EN_MASK);
+
+ /* complete the above write before the delay */
+ mb();
/*
* wait for the bhs to settle - note that
@@ -242,6 +286,12 @@
*/
udelay(BHS_SETTLING_DELAY_US);
+ /*
+ * enable ldo bypass - the krait is powered still by LDO since
+ * LDO is enabled
+ */
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
+
/* disable ldo - only the BHS provides voltage to the cpu after this */
krait_masked_write(kvreg, APC_PWR_GATE_CTL,
LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
@@ -253,7 +303,8 @@
static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
{
- if (kvreg->mode == LDO_MODE && get_krait_ldo_uv(kvreg) == kvreg->uV)
+ if (kvreg->mode == LDO_MODE
+ && get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
return 0;
/*
@@ -263,7 +314,7 @@
if (kvreg->mode == LDO_MODE)
switch_to_using_hs(kvreg);
- set_krait_ldo_uv(kvreg, kvreg->uV);
+ set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
/*
* enable ldo - note that both LDO and BHS are are supplying voltage to
@@ -272,6 +323,9 @@
*/
krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_PWR_DWN_MASK, 0);
+ /* complete the writes before the delay */
+ mb();
+
/* wait for the ldo to settle */
udelay(LDO_SETTLING_DELAY_US);
@@ -281,6 +335,7 @@
*/
krait_masked_write(kvreg, APC_PWR_GATE_CTL,
BHS_EN_MASK | LDO_BYP_MASK, 0);
+ krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_SEG_EN_MASK, 0);
kvreg->mode = LDO_MODE;
pr_debug("%s using LDO\n", kvreg->name);
@@ -317,6 +372,22 @@
uV = PMIC_VOLTAGE_MAX;
}
+ if (uV < pvreg->pmic_min_uV_for_retention) {
+ if (pvreg->retention_enabled) {
+ pr_debug("Disabling Retention pmic = %duV, pmic_min_uV_for_retention = %duV",
+ uV, pvreg->pmic_min_uV_for_retention);
+ msm_pm_enable_retention(false);
+ pvreg->retention_enabled = false;
+ }
+ } else {
+ if (!pvreg->retention_enabled) {
+ pr_debug("Enabling Retention pmic = %duV, pmic_min_uV_for_retention = %duV",
+ uV, pvreg->pmic_min_uV_for_retention);
+ msm_pm_enable_retention(true);
+ pvreg->retention_enabled = true;
+ }
+ }
+
setpoint = DIV_ROUND_UP(uV, LV_RANGE_STEP);
rc = msm_spm_apcs_set_vdd(setpoint);
@@ -338,18 +409,19 @@
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
if (!kvreg->online)
continue;
- if (kvreg->uV > kvreg->ldo_threshold_uV
- || kvreg->uV > vmax - kvreg->headroom_uV) {
- rc = switch_to_using_hs(kvreg);
+ if (kvreg->uV <= kvreg->ldo_threshold_uV
+ && kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
+ <= vmax) {
+ rc = switch_to_using_ldo(kvreg);
if (rc < 0) {
- pr_err("could not switch %s to hs rc = %d\n",
+ pr_err("could not switch %s to ldo rc = %d\n",
kvreg->name, rc);
return rc;
}
} else {
- rc = switch_to_using_ldo(kvreg);
+ rc = switch_to_using_hs(kvreg);
if (rc < 0) {
- pr_err("could not switch %s to ldo rc = %d\n",
+ pr_err("could not switch %s to hs rc = %d\n",
kvreg->name, rc);
return rc;
}
@@ -378,6 +450,10 @@
return rc;
}
+
+ /* complete the above writes before the delay */
+ mb();
+
/* delay until the voltage is settled when it is raised */
settling_us = DIV_ROUND_UP(vmax - pvreg->pmic_vmax_uV, SLEW_RATE);
udelay(settling_us);
@@ -438,6 +514,9 @@
return rc;
}
+ /* complete the writes before the delay */
+ mb();
+
/*
* delay until the phases are settled when
* the count is raised
@@ -464,6 +543,8 @@
pvreg->name = "pmic_gang";
pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN;
pvreg->pmic_phase_count = 1;
+ pvreg->retention_enabled = true;
+ pvreg->pmic_min_uV_for_retention = INT_MAX;
mutex_init(&pvreg->krait_power_vregs_lock);
INIT_LIST_HEAD(&pvreg->krait_power_vregs);
@@ -722,24 +803,57 @@
.is_enabled = krait_power_is_enabled,
};
+static struct dentry *dent;
+static int get_retention_dbg_uV(void *data, u64 *val)
+{
+ struct pmic_gang_vreg *pvreg = data;
+ struct krait_power_vreg *kvreg;
+
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ if (!list_empty(&pvreg->krait_power_vregs)) {
+ /* return the retention voltage on just the first cpu */
+ kvreg = list_entry((&pvreg->krait_power_vregs)->next,
+ typeof(*kvreg), link);
+ *val = get_krait_retention_ldo_uv(kvreg);
+ }
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ return 0;
+}
+
+static int set_retention_dbg_uV(void *data, u64 val)
+{
+ struct pmic_gang_vreg *pvreg = data;
+ struct krait_power_vreg *kvreg;
+ int retention_uV = val;
+
+ if (!is_between(LDO_UV_MIN, LDO_UV_MAX, retention_uV))
+ return -EINVAL;
+
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+ kvreg->retention_uV = retention_uV;
+ set_krait_retention_uv(kvreg, retention_uV);
+ }
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(retention_fops,
+ get_retention_dbg_uV, set_retention_dbg_uV, "%llu\n");
+
static void kvreg_hw_init(struct krait_power_vreg *kvreg)
{
/*
* bhs_cnt value sets the ramp-up time from power collapse,
* initialize the ramp up time
*/
- krait_masked_write(kvreg, APC_PWR_GATE_CTL,
- BHS_CNT_MASK, BHS_CNT_DEFAULT << BHS_CNT_BIT_POS);
-
- krait_masked_write(kvreg, APC_PWR_GATE_CTL,
- CLK_SRC_SEL_MASK, CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS);
-
- /* BHS has six different segments, turn them all on */
- krait_masked_write(kvreg, APC_PWR_GATE_CTL,
- BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
-
set_krait_retention_uv(kvreg, kvreg->retention_uV);
set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
+
+ /* setup the bandgap that configures the reference to the LDO */
+ writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
+ /* Enable MDD */
+ writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
+ mb();
}
static void glb_init(struct platform_device *pdev)
@@ -751,31 +865,14 @@
pr_debug("version= 0x%x\n", version);
}
-static int is_between(int left, int right, int value)
-{
- if (left >= right && left >= value && value >= right)
- return 1;
- if (left <= right && left <= value && value <= right)
- return 1;
- return 0;
-}
-
-#define LDO_HDROOM_MIN 50000
-#define LDO_HDROOM_MAX 250000
-
-#define LDO_UV_MIN 465000
-#define LDO_UV_MAX 750000
-
-#define LDO_TH_MIN 600000
-#define LDO_TH_MAX 800000
-
static int __devinit krait_power_probe(struct platform_device *pdev)
{
struct krait_power_vreg *kvreg;
- struct resource *res;
+ struct resource *res, *res_mdd;
struct regulator_init_data *init_data = pdev->dev.platform_data;
int rc = 0;
int headroom_uV, retention_uV, ldo_default_uV, ldo_threshold_uV;
+ int ldo_delta_uV;
/* Initialize the pmic gang if it hasn't been initialized already */
if (the_gang == NULL) {
@@ -789,6 +886,12 @@
glb_init(pdev);
}
+ if (dent == NULL) {
+ dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL);
+ debugfs_create_file("retention_uV",
+ 0644, dent, the_gang, &retention_fops);
+ }
+
if (pdev->dev.of_node) {
/* Get init_data from device tree. */
init_data = of_get_regulator_init_data(&pdev->dev,
@@ -851,6 +954,19 @@
ldo_threshold_uV);
return -EINVAL;
}
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,ldo-delta-voltage",
+ &ldo_delta_uV);
+ if (rc < 0) {
+ pr_err("ldo-delta-voltage missing rc=%d\n", rc);
+ return rc;
+ }
+ if (!is_between(LDO_DELTA_MIN, LDO_DELTA_MAX, ldo_delta_uV)) {
+ pr_err("bad ldo-delta-voltage = %d specified\n",
+ ldo_delta_uV);
+ return -EINVAL;
+ }
}
if (!init_data) {
@@ -864,12 +980,18 @@
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acs");
if (!res) {
dev_err(&pdev->dev, "missing physical register addresses\n");
return -EINVAL;
}
+ res_mdd = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdd");
+ if (!res_mdd) {
+ dev_err(&pdev->dev, "missing mdd register addresses\n");
+ return -EINVAL;
+ }
+
kvreg = devm_kzalloc(&pdev->dev,
sizeof(struct krait_power_vreg), GFP_KERNEL);
if (!kvreg) {
@@ -880,6 +1002,9 @@
kvreg->reg_base = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
+ kvreg->mdd_base = devm_ioremap(&pdev->dev,
+ res_mdd->start, resource_size(res));
+
kvreg->pvreg = the_gang;
kvreg->name = init_data->constraints.name;
kvreg->desc.name = kvreg->name;
@@ -893,10 +1018,14 @@
kvreg->retention_uV = retention_uV;
kvreg->ldo_default_uV = ldo_default_uV;
kvreg->ldo_threshold_uV = ldo_threshold_uV;
+ kvreg->ldo_delta_uV = ldo_delta_uV;
platform_set_drvdata(pdev, kvreg);
mutex_lock(&the_gang->krait_power_vregs_lock);
+ the_gang->pmic_min_uV_for_retention
+ = min(the_gang->pmic_min_uV_for_retention,
+ kvreg->retention_uV + kvreg->headroom_uV);
list_add_tail(&kvreg->link, &the_gang->krait_power_vregs);
mutex_unlock(&the_gang->krait_power_vregs_lock);
@@ -959,25 +1088,36 @@
{
platform_driver_unregister(&krait_power_driver);
}
-
module_exit(krait_power_exit);
void secondary_cpu_hs_init(void *base_ptr)
{
- /* 605mV retention and 705mV operational voltage */
- writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
- /* HS_EN_DLY=3; LDO_BYP_DLY=1; */
- writel_relaxed(0x430000, base_ptr + APC_PWR_GATE_DLY);
- /* MODE = BHS; EN=1; */
- writel_relaxed(0x21, base_ptr + APC_PWR_GATE_MODE);
-
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
- writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
+ writel_relaxed(
+ BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
+ | LDO_PWR_DWN_MASK
+ | CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
+ | BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
+ | BHS_EN_MASK,
+ base_ptr + APC_PWR_GATE_CTL);
+
+ /* complete the above write before the delay */
mb();
- udelay(1);
+
+ /*
+ * wait for the bhs to settle
+ */
+ udelay(BHS_SETTLING_DELAY_US);
/* Finally turn on the bypass so that BHS supplies power */
- writel_relaxed(0x403F3F7F, base_ptr + APC_PWR_GATE_CTL);
+ writel_relaxed(
+ BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
+ | LDO_PWR_DWN_MASK
+ | CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
+ | LDO_BYP_MASK
+ | BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
+ | BHS_EN_MASK,
+ base_ptr + APC_PWR_GATE_CTL);
}
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 61c2aa8..fcb4299 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.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
@@ -37,6 +37,10 @@
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
+static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
+static DEFINE_PER_CPU(int , lpm_permitted_level);
+static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+
static void msm_lpm_level_update(void)
{
unsigned int lpm_level;
@@ -53,31 +57,41 @@
bool from_idle, bool notify_rpm)
{
int ret = 0;
- int debug_mask;
- struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
+ struct msm_lpm_sleep_data sleep_data;
- ret = msm_rpm_enter_sleep();
- if (ret) {
- pr_warn("%s(): RPM failed to enter sleep err:%d\n",
- __func__, ret);
- goto bail;
+ sleep_data.limits = limits;
+ sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
+ atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+ MSM_LPM_STATE_ENTER, &sleep_data);
+
+ if (notify_rpm) {
+ int debug_mask;
+ struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
+
+ ret = msm_rpm_enter_sleep();
+ if (ret) {
+ pr_warn("%s(): RPM failed to enter sleep err:%d\n",
+ __func__, ret);
+ goto bail;
+ }
+ if (from_idle)
+ debug_mask = msm_lpm_lvl_dbg_msk &
+ MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ else
+ debug_mask = msm_lpm_lvl_dbg_msk &
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+
+ if (debug_mask)
+ pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
+ __func__, l->pxo, l->l2_cache,
+ l->vdd_mem_lower_bound,
+ l->vdd_mem_upper_bound,
+ l->vdd_dig_lower_bound,
+ l->vdd_dig_upper_bound);
+
+ ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle,
+ notify_rpm);
}
- if (from_idle)
- debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_IDLE_LIMITS;
- else
- debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
-
- if (debug_mask)
- pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
- __func__, l->pxo, l->l2_cache,
- l->vdd_mem_lower_bound,
- l->vdd_mem_upper_bound,
- l->vdd_dig_lower_bound,
- l->vdd_dig_upper_bound);
-
- ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
bail:
return ret;
}
@@ -88,6 +102,8 @@
msm_rpm_exit_sleep();
msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm, collapsed);
+ atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+ MSM_LPM_STATE_EXIT, NULL);
}
void msm_lpm_show_resources(void)
@@ -96,6 +112,48 @@
return;
}
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
+{
+ return limits->pxo;
+}
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
+{
+ return limits->l2_cache;
+}
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+ return limits->vdd_mem_upper_bound;
+}
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+ return limits->vdd_dig_upper_bound;
+}
+
+static bool lpm_level_permitted(int cur_level_count)
+{
+ if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
+ return true;
+ return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
+}
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+ struct notifier_block *nb, bool is_latency_measure)
+{
+ per_cpu(lpm_permitted_level, cpu) = level_iter;
+ return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
+ cpu), nb);
+}
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
+{
+ per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
+ return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
+ nb);
+}
+
s32 msm_cpuidle_get_deep_idle_latency(void)
{
int i;
@@ -127,7 +185,7 @@
struct msm_rpmrs_level *best_level = NULL;
uint32_t pwr;
int i;
-
+ int best_level_iter = msm_lpm_level_count + 1;
if (!msm_lpm_levels)
return NULL;
@@ -170,14 +228,31 @@
level->rs_limits.latency_us[cpu] = level->latency_us;
level->rs_limits.power[cpu] = pwr;
best_level = level;
-
+ best_level_iter = i;
if (power)
*power = pwr;
}
}
+ if (best_level && !lpm_level_permitted(best_level_iter))
+ best_level = NULL;
+ else
+ per_cpu(msm_lpm_sleep_time, cpu) =
+ time_param->modified_time_us ?
+ time_param->modified_time_us : time_param->sleep_us;
return best_level ? &best_level->rs_limits : NULL;
}
+
+static struct lpm_test_platform_data lpm_test_pdata;
+
+static struct platform_device msm_lpm_test_device = {
+ .name = "lpm_test",
+ .id = -1,
+ .dev = {
+ .platform_data = &lpm_test_pdata,
+ },
+};
+
static struct msm_pm_sleep_ops msm_lpm_ops = {
.lowest_limits = msm_lpm_lowest_limits,
.enter_sleep = msm_lpm_enter_sleep,
@@ -194,6 +269,7 @@
int ret = 0;
uint32_t num_levels = 0;
int idx = 0;
+ unsigned int m_cpu = 0;
for_each_child_of_node(pdev->dev.of_node, node)
num_levels++;
@@ -279,6 +355,17 @@
msm_lpm_levels = levels;
msm_lpm_level_count = idx;
+ lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
+ lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
+ key = "qcom,use-qtimer";
+ lpm_test_pdata.use_qtimer =
+ of_property_read_bool(pdev->dev.of_node, key);
+
+ for_each_possible_cpu(m_cpu)
+ per_cpu(lpm_permitted_level, m_cpu) =
+ msm_lpm_level_count + 1;
+
+ platform_device_register(&msm_lpm_test_device);
msm_pm_set_sleep_ops(&msm_lpm_ops);
return 0;
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 120832f..42e43c2 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -15,6 +15,7 @@
#define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
#include "pm.h"
+#include "test-lpm.h"
enum {
MSM_LPM_PXO_OFF = 0,
@@ -50,6 +51,93 @@
uint32_t time_overhead_us;
};
+enum {
+ MSM_LPM_STATE_ENTER = 0,
+ MSM_LPM_STATE_EXIT = 1,
+};
+
+#define MSM_PM(field) MSM_LPM_##field
+
+/**
+ * msm_pm_get_pxo() - get the limits for pxo
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource pxo on
+ * 8974
+ */
+
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_l2_cache() - get the limits for l2 cache
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource l2 cache
+ * on 8974
+ */
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_mem() - get the limits for pxo
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource vdd mem
+ * on 8974
+ */
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_dig() - get the limits for vdd dig
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource on 8974
+ */
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
+
+/**
+ * struct msm_lpm_sleep_data - abstraction to get sleep data
+ * @limits: pointer to the msm_rpmrs_limits structure
+ * @kernel_sleep: kernel sleep time as decided by the power calculation
+ * algorithm
+ *
+ * This structure is an abstraction to get the limits and kernel sleep time
+ * during enter sleep.
+ */
+
+struct msm_lpm_sleep_data {
+ struct msm_rpmrs_limits *limits;
+ uint32_t kernel_sleep;
+};
+
+/**
+ * msm_lpm_register_notifier() - register for notifications
+ * @cpu: cpu to debug
+ * @level_iter: low power level index to debug
+ * @nb: notifier block to callback on notifications
+ * @is_latency_measure: is it latency measure
+ *
+ * This function sets the permitted level to the index of the
+ * level under test and registers notifier for callback.
+ */
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+ struct notifier_block *nb, bool is_latency_measure);
+
+/**
+ * msm_lpm_unregister_notifier() - unregister from notifications
+ * @cpu: cpu to debug
+ * @nb: notifier block to callback on notifications
+ *
+ * This function sets the permitted level to a value one more than
+ * available levels count which indicates that all levels are
+ * permitted and it also unregisters notifier for callback.
+ */
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
+
#ifdef CONFIG_MSM_RPM_SMD
/**
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index aef4ac9..03d158e 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -444,6 +444,10 @@
{
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_drv->boot_type = CHARM_NORMAL_BOOT;
complete(&mdm_needs_reload);
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 ea17efe..d416c19 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -1932,17 +1932,18 @@
}
for (i = 0; i < info->node_info->num_mports; i++) {
- /* If in bypass mode, update priority */
- if (info->node_info->mode != BIMC_QOS_MODE_BYPASS)
+ /* 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 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);
+ /* 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 */
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c
index 88fab96..7c2b4c9 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -101,7 +101,7 @@
if (ret) {
MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n",
rsc_type);
- return ret;
+ goto free_rpm_request;
}
MSM_BUS_DBG("Added Key: %d, Val: %llu, size: %d\n", key,
@@ -112,22 +112,26 @@
if (ret) {
MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n",
rsc_type);
- return ret;
+ goto free_rpm_request;
}
}
msg_id = msm_rpm_send_request(rpm_req);
if (!msg_id) {
MSM_BUS_WARN("RPM: No message ID for req\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto free_rpm_request;
}
ret = msm_rpm_wait_for_ack(msg_id);
if (ret) {
MSM_BUS_WARN("RPM: Ack failed\n");
- return ret;
+ goto free_rpm_request;
}
+free_rpm_request:
+ msm_rpm_free_request(rpm_req);
+
return ret;
}
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index 6aa14a6..ef10cdc 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -333,7 +333,14 @@
wdog_dd->last_pet, nanosec_rem / 1000);
if (wdog_dd->do_ipi_ping)
dump_cpu_alive_mask(wdog_dd);
- panic("Apps watchdog bark received!");
+ printk(KERN_INFO "Causing a watchdog bite!");
+ __raw_writel(1, wdog_dd->base + WDT0_BITE_TIME);
+ mb();
+ __raw_writel(1, wdog_dd->base + WDT0_RST);
+ mb();
+ /* Delay to make sure bite occurs */
+ mdelay(1);
+ panic("Failed to cause a watchdog bite! - Falling back to kernel panic!");
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d460c70..a8d4fdb 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -37,14 +37,11 @@
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
return -ENOSYS;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
-{
- return -ENOSYS;
-}
+void msm_pm_enable_retention(bool enable) {}
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
new file mode 100644
index 0000000..8c942ad
--- /dev/null
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -0,0 +1,66 @@
+/* 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/types.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+/*
+ * Subsequent patches should add an entry to end of this string.
+ * Format is incrementing sequence number followed by text of
+ * patch commit title with newline.
+ * Note trailing ';' is on its own line to simplify addition of
+ * future strings.
+ */
+static char *descriptions =
+ "0 msm: perf: add debug patch logging framework\n"
+ "1 Perf: Restore counter after powercollapse for generic ARM PMU's\n"
+ "2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
+;
+
+static ssize_t desc_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ return simple_read_from_buffer(buf, count, pos, descriptions,
+ strlen(descriptions));
+}
+
+static const struct file_operations perf_debug_desc_fops = {
+ .read = desc_read,
+};
+
+static int msm_perf_debugfs_init(void)
+{
+ int ret = 0;
+ struct dentry *dir;
+ struct dentry *file;
+
+ dir = debugfs_create_dir("msm-perf-patches", NULL);
+ if (IS_ERR_OR_NULL(dir)) {
+ pr_err("failed to create msm-perf-patches dir in debugfs\n");
+ ret = PTR_ERR(dir);
+ goto init_exit;
+ }
+
+ file = debugfs_create_file("descriptions", 0444, dir, NULL,
+ &perf_debug_desc_fops);
+ if (IS_ERR_OR_NULL(file)) {
+ debugfs_remove(dir);
+ pr_err("failed to create descriptions file for msm-perf-patches\n");
+ ret = PTR_ERR(file);
+ goto init_exit;
+ }
+
+init_exit:
+ return ret;
+}
+late_initcall(msm_perf_debugfs_init);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index ed85c95..7cf61ab 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
/*
- * 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,6 +24,7 @@
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
#include <mach/subsystem_restart.h>
#include <mach/clk.h>
@@ -87,6 +88,8 @@
bool crash_shutdown;
bool ignore_errors;
int is_loadable;
+ int err_fatal_irq;
+ int force_stop_gpio;
};
static int pbl_mba_boot_timeout_ms = 100;
@@ -442,18 +445,17 @@
subsystem_restart_dev(drv->subsys);
}
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
{
- struct mba_data *drv = data;
+ struct mba_data *drv = dev_id;
- /* Ignore if we're the one that set SMSM_RESET */
+ /* Ignore if we're the one that set the force stop GPIO */
if (drv->crash_shutdown)
- return;
+ return IRQ_HANDLED;
- if (new_state & SMSM_RESET) {
- pr_err("Probable fatal error on the modem.\n");
- restart_modem(drv);
- }
+ pr_err("Fatal error on the modem.\n");
+ restart_modem(drv);
+ return IRQ_HANDLED;
}
static int modem_shutdown(const struct subsys_desc *subsys)
@@ -493,7 +495,7 @@
{
struct mba_data *drv = subsys_to_drv(subsys);
drv->crash_shutdown = true;
- smsm_reset_modem(SMSM_RESET);
+ gpio_set_value(drv->force_stop_gpio, 1);
}
static struct ramdump_segment smem_segments[] = {
@@ -630,10 +632,11 @@
goto err_irq;
}
- ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
- smsm_state_cb, drv);
+ ret = devm_request_irq(&pdev->dev, drv->err_fatal_irq,
+ modem_err_fatal_intr_handler,
+ IRQF_TRIGGER_RISING, "pil-mss", drv);
if (ret < 0) {
- dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
+ dev_err(&pdev->dev, "Unable to register SMP2P err fatal handler!\n");
goto err_irq;
}
@@ -643,14 +646,11 @@
ret = PTR_ERR(drv->adsp_state_notifier);
dev_err(&pdev->dev, "%s: Registration with the SSR notification driver failed (%d)",
__func__, ret);
- goto err_smsm;
+ goto err_irq;
}
return 0;
-err_smsm:
- smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET, smsm_state_cb,
- drv);
err_irq:
destroy_ramdump_device(drv->smem_ramdump_dev);
err_ramdump_smem:
@@ -759,7 +759,7 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
- int ret;
+ int ret, err_fatal_gpio;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
@@ -774,6 +774,22 @@
return ret;
}
+ /* Get the IRQ from the GPIO for registering inbound handler */
+ err_fatal_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-fatal", 0);
+ if (err_fatal_gpio < 0)
+ return err_fatal_gpio;
+
+ drv->err_fatal_irq = gpio_to_irq(err_fatal_gpio);
+ if (drv->err_fatal_irq < 0)
+ return drv->err_fatal_irq;
+
+ /* 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);
+ if (drv->force_stop_gpio < 0)
+ return drv->force_stop_gpio;
+
return pil_subsys_init(drv, pdev);
}
@@ -783,8 +799,6 @@
subsys_notif_unregister_notifier(drv->adsp_state_notifier,
&adsp_state_notifier_block);
- smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
- smsm_state_cb, drv);
subsys_unregister(drv->subsys);
destroy_ramdump_device(drv->smem_ramdump_dev);
destroy_ramdump_device(drv->ramdump_dev);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index e35d843..af6f8af 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-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
@@ -118,6 +118,7 @@
static struct msm_pm_init_data_type msm_pm_init_data;
static struct hrtimer pm_hrtimer;
static struct msm_pm_sleep_ops pm_sleep_ops;
+static bool msm_pm_ldo_retention_enabled = true;
/*
* Write out the attribute.
*/
@@ -474,8 +475,6 @@
}
}
-static void *msm_pm_idle_rs_limits;
-
static void msm_pm_swfi(void)
{
msm_pm_config_hw_before_swfi();
@@ -774,8 +773,9 @@
}
}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static int msm_pm_idle_prepare(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ void **msm_pm_idle_rs_limits)
{
int i;
unsigned int power_usage = -1;
@@ -802,7 +802,6 @@
struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
enum msm_pm_sleep_mode mode;
bool allow;
- void *rs_limits = NULL;
uint32_t power;
int idx;
@@ -820,6 +819,14 @@
}
/* fall through */
case MSM_PM_SLEEP_MODE_RETENTION:
+ /*
+ * The Krait BHS regulator doesn't have enough head
+ * room to drive the retention voltage on LDO and so
+ * has disabled retention
+ */
+ if (!msm_pm_ldo_retention_enabled)
+ break;
+
if (!allow)
break;
@@ -841,17 +848,20 @@
/* fall through */
if (pm_sleep_ops.lowest_limits)
- rs_limits = pm_sleep_ops.lowest_limits(true,
- mode, &time_param, &power);
+ *msm_pm_idle_rs_limits =
+ pm_sleep_ops.lowest_limits(
+ true, mode,
+ &time_param, &power);
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: %s, latency %uus, "
"sleep %uus, limit %p\n",
dev->cpu, __func__, state->desc,
time_param.latency_us,
- time_param.sleep_us, rs_limits);
+ time_param.sleep_us,
+ *msm_pm_idle_rs_limits);
- if (!rs_limits)
+ if (!*msm_pm_idle_rs_limits)
allow = false;
break;
@@ -871,8 +881,6 @@
ret = mode;
}
- if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
- msm_pm_idle_rs_limits = rs_limits;
}
}
@@ -886,11 +894,27 @@
return ret;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
int64_t time;
- int exit_stat;
bool collapsed = 1;
+ int exit_stat = -1;
+ enum msm_pm_sleep_mode sleep_mode;
+ void *msm_pm_idle_rs_limits = NULL;
+ int sleep_delay = 1;
+ int ret = -ENODEV;
+ int64_t timer_expiration = 0;
+ int notify_rpm = false;
+ bool timer_halted = false;
+
+ sleep_mode = msm_pm_idle_prepare(dev, drv, index,
+ &msm_pm_idle_rs_limits);
+
+ if (!msm_pm_idle_rs_limits) {
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ goto cpuidle_enter_bail;
+ }
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: mode %d\n",
@@ -898,76 +922,80 @@
time = ktime_to_ns(ktime_get());
- switch (sleep_mode) {
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- msm_pm_swfi();
- exit_stat = MSM_PM_STAT_IDLE_WFI;
- break;
-
- case MSM_PM_SLEEP_MODE_RETENTION:
- msm_pm_retention();
- exit_stat = MSM_PM_STAT_RETENTION;
- break;
-
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- collapsed = msm_pm_power_collapse_standalone(true);
- exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
- break;
-
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
- int64_t timer_expiration = 0;
- bool timer_halted = false;
- uint32_t sleep_delay;
- int ret = -ENODEV;
- int notify_rpm =
- (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ notify_rpm = true;
timer_expiration = msm_pm_timer_enter_idle();
sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
if (sleep_delay == 0) /* 0 would mean infinite time */
sleep_delay = 1;
+ }
- if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
- clock_debug_print_enabled();
+ if (pm_sleep_ops.enter_sleep)
+ ret = pm_sleep_ops.enter_sleep(sleep_delay,
+ msm_pm_idle_rs_limits,
+ true, notify_rpm);
+ if (!ret) {
- if (pm_sleep_ops.enter_sleep)
- ret = pm_sleep_ops.enter_sleep(sleep_delay,
- msm_pm_idle_rs_limits,
- true, notify_rpm);
- if (!ret) {
+ switch (sleep_mode) {
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ msm_pm_swfi();
+ exit_stat = MSM_PM_STAT_IDLE_WFI;
+ break;
+
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ msm_pm_retention();
+ exit_stat = MSM_PM_STAT_RETENTION;
+ break;
+
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ collapsed = msm_pm_power_collapse_standalone(true);
+ exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ break;
+
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
+ clock_debug_print_enabled();
+
collapsed = msm_pm_power_collapse(true);
timer_halted = true;
- if (pm_sleep_ops.exit_sleep)
- pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
- true, notify_rpm, collapsed);
+ exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ msm_pm_timer_exit_idle(timer_halted);
+ break;
+
+ case MSM_PM_SLEEP_MODE_NOT_SELECTED:
+ goto cpuidle_enter_bail;
+ break;
+
+ default:
+ __WARN();
+ goto cpuidle_enter_bail;
+ break;
}
+ if (pm_sleep_ops.exit_sleep)
+ pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
+ true, notify_rpm, collapsed);
+
+ time = ktime_to_ns(ktime_get()) - time;
+ msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
+ collapsed);
+ if (exit_stat >= 0)
+ msm_pm_add_stat(exit_stat, time);
+ do_div(time, 1000);
+ dev->last_residency = (int) time;
+ return sleep_mode;
+
+ } else if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
msm_pm_timer_exit_idle(timer_halted);
- exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
- break;
- }
-
- case MSM_PM_SLEEP_MODE_NOT_SELECTED:
- goto cpuidle_enter_bail;
- break;
-
- default:
- __WARN();
- goto cpuidle_enter_bail;
- break;
- }
-
- time = ktime_to_ns(ktime_get()) - time;
- msm_pm_add_stat(exit_stat, time);
- msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
- collapsed);
-
- do_div(time, 1000);
- return (int) time;
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ } else
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
cpuidle_enter_bail:
- return 0;
+ dev->last_residency = 0;
+ return sleep_mode;
}
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
@@ -995,6 +1023,34 @@
msm_pm_swfi();
}
+static void msm_pm_ack_retention_disable(void *data)
+{
+ /*
+ * This is a NULL function to ensure that the core has woken up
+ * and is safe to disable retention.
+ */
+}
+/**
+ * msm_pm_enable_retention() - Disable/Enable retention on all cores
+ * @enable: Enable/Disable retention
+ *
+ */
+void msm_pm_enable_retention(bool enable)
+{
+ msm_pm_ldo_retention_enabled = enable;
+ /*
+ * If retention is being disabled, wakeup all online core to ensure
+ * that it isn't executing retention. Offlined cores need not be woken
+ * up as they enter the deepest sleep mode, namely RPM assited power
+ * collapse
+ */
+ if (!enable)
+ smp_call_function_many(cpu_online_mask,
+ msm_pm_ack_retention_disable,
+ NULL, true);
+}
+EXPORT_SYMBOL(msm_pm_enable_retention);
+
static int msm_pm_enter(suspend_state_t state)
{
bool allow[MSM_PM_SLEEP_MODE_NR];
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index 6f4743f..ccc2519 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -30,7 +30,7 @@
[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
.idle_supported = 1,
- .suspend_supported = 1,
+ .suspend_supported = 0,
.idle_enabled = 0,
.suspend_enabled = 0,
},
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 86d8f98..43bb7de 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/pm.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: San Mehat <san@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -108,12 +108,12 @@
};
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
+void msm_pm_enable_retention(bool enable);
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 21f65f8..febeb19 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -11,7 +11,6 @@
*/
#include <linux/platform_device.h>
-#include <linux/irq.h>
#include <asm/pmu.h>
#include <mach/irqs.h>
#include <mach/socinfo.h>
@@ -30,20 +29,9 @@
#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
|| defined(CONFIG_ARCH_MSM8625) || \
(defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))
+
static DEFINE_PER_CPU(u32, pmu_irq_cookie);
-static void enable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
- enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-static void disable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
- disable_percpu_irq(irq);
-}
-
static int
multicore_request_irq(int irq, irq_handler_t *handle_irq)
{
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 5f126bc..7d2766d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.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
@@ -335,6 +335,8 @@
struct wake_lock suspend_lock;
struct pm_qos_request pm_qos_req;
+
+ struct completion complete;
};
static struct audio_mvs_info_type audio_mvs_info;
@@ -1235,7 +1237,7 @@
kfree(rpc_hdr);
rpc_hdr = NULL;
}
-
+ complete_and_exit(&audio->complete, 0);
MM_DBG("MVS thread stopped\n");
return 0;
@@ -1360,6 +1362,7 @@
audio_mvs_stop(audio);
audio->state = AUDIO_MVS_CLOSED;
msm_rpc_read_wakeup(audio->rpc_endpt);
+ wait_for_completion(&audio->complete);
msm_rpc_close(audio->rpc_endpt);
audio->task = NULL;
audio_mvs_free_buf(audio);
@@ -1716,6 +1719,8 @@
INIT_LIST_HEAD(&audio_mvs_info.out_queue);
INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+ init_completion(&audio_mvs_info.complete);
+
wake_lock_init(&audio_mvs_info.suspend_lock,
WAKE_LOCK_SUSPEND,
"audio_mvs_suspend");
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index fee7404..ceb73f0 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -293,6 +293,11 @@
{
struct audio_copp *audio_copp = priv;
+ if (audio_copp == NULL) {
+ MM_ERR("NULL audio copp pointer\n");
+ return;
+ }
+
if (AUDPP_MSG_CFG_MSG == id && msg[0] == AUDPP_MSG_ENA_DIS)
return;
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index b4b7338f..2a83238 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -4,7 +4,7 @@
* common code to deal with the AUDPP dsp task (audio postproc)
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, 2012 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 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
@@ -176,12 +176,15 @@
struct audpp_state *audpp = &the_audpp_state;
int i;
+ mutex_lock(audpp->lock);
for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
if (NULL == audpp->cb_tbl[i]) {
audpp->cb_tbl[i] = ecb;
+ mutex_unlock(audpp->lock);
return 0;
}
}
+ mutex_unlock(audpp->lock);
return -1;
}
EXPORT_SYMBOL(audpp_register_event_callback);
@@ -191,12 +194,15 @@
struct audpp_state *audpp = &the_audpp_state;
int i;
+ mutex_lock(audpp->lock);
for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
if (ecb == audpp->cb_tbl[i]) {
audpp->cb_tbl[i] = NULL;
+ mutex_unlock(audpp->lock);
return 0;
}
}
+ mutex_unlock(audpp->lock);
return -1;
}
EXPORT_SYMBOL(audpp_unregister_event_callback);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_tal.c b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
index 03f0513..d734739 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_tal.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
@@ -133,12 +133,12 @@
spin_unlock_irqrestore(&apr_ch->lock, flags);
break;
case SMD_EVENT_OPEN:
- pr_info("apr_tal: SMD_EVENT_OPEN\n");
+ pr_debug("apr_tal: SMD_EVENT_OPEN\n");
apr_ch->smd_state = 1;
wake_up(&apr_ch->wait);
break;
case SMD_EVENT_CLOSE:
- pr_info("apr_tal: SMD_EVENT_CLOSE\n");
+ pr_debug("apr_tal: SMD_EVENT_CLOSE\n");
break;
}
}
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
index ed494e4..f554cf3 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v2.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -50,16 +50,16 @@
pr_err("%s: adsp not up\n", __func__);
return NULL;
}
- pr_info("%s: adsp Up\n", __func__);
+ pr_debug("%s: adsp Up\n", __func__);
} else if ((dest_id == APR_DEST_MODEM) &&
(apr_get_modem_state() == APR_SUBSYS_DOWN)) {
- pr_info("%s: Wait for modem to bootup\n", __func__);
+ pr_debug("%s: Wait for modem to bootup\n", __func__);
rc = apr_wait_for_device_up(dest_id);
if (rc == 0) {
pr_err("%s: Modem is not Up\n", __func__);
return NULL;
}
- pr_info("%s: modem Up\n", __func__);
+ pr_debug("%s: modem Up\n", __func__);
}
if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 6a23e37..33bbac0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
@@ -109,8 +109,8 @@
rc = q6asm_cmd(audio->ac, CMD_CLOSE);
if (rc < 0)
- pr_err("%s:session id %d: Failed to close the"
- "session rc=%d\n", __func__, audio->ac->session,
+ pr_err("%s:session id %d: Failed to close the session rc=%d\n",
+ __func__, audio->ac->session,
rc);
audio->stopped = 1;
memset(audio->out_frame_info, 0,
@@ -135,8 +135,8 @@
ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
audio->pcm_cfg.buffer_count);
if (rc < 0) {
- pr_err("%s:session id %d: Buffer Alloc"
- "failed\n", __func__,
+ pr_err("%s:session id %d: Buffer Alloc failed\n",
+ __func__,
audio->ac->session);
rc = -ENOMEM;
break;
@@ -172,8 +172,8 @@
ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
audio->pcm_cfg.buffer_count);
if (rc < 0) {
- pr_err("%s:session id %d: Buffer Alloc"
- "failed\n", __func__,
+ pr_err("%s:session id %d: Buffer Alloc failed\n",
+ __func__,
audio->ac->session);
rc = -ENOMEM;
break;
@@ -303,15 +303,15 @@
}
audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
- pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]"
- "framesperbuf[%d]\n", __func__,
+ pr_debug("%s:session id %d: Set-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__,
audio->ac->session, cfg.meta_info_enable,
cfg.frames_per_buf);
break;
}
case AUDIO_GET_BUF_CFG: {
- pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]"
- "framesperbuf[%d]\n", __func__,
+ pr_debug("%s:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
+ __func__,
audio->ac->session, audio->buf_cfg.meta_info_enable,
audio->buf_cfg.frames_per_buf);
@@ -334,8 +334,8 @@
break;
}
if (audio->feedback != NON_TUNNEL_MODE) {
- pr_err("%s:session id %d: Not sufficient permission to"
- "change the record mode\n", __func__,
+ pr_err("%s:session id %d: Not sufficient permission to change the record mode\n",
+ __func__,
audio->ac->session);
rc = -EACCES;
break;
@@ -399,15 +399,22 @@
audio->read_wait,
((atomic_read(&audio->out_count) > 0) ||
(audio->stopped) ||
- audio->rflush || audio->eos_rsp));
+ audio->rflush || audio->eos_rsp ||
+ audio->event_abort));
+
+ if (audio->event_abort) {
+ rc = -EIO;
+ break;
+ }
+
if (rc < 0)
break;
if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
audio->rflush) {
- pr_debug("%s:session id %d: driver in stop state or"
- "flush,No more buf to read", __func__,
+ pr_debug("%s:session id %d: driver in stop state or flush,No more buf to read",
+ __func__,
audio->ac->session);
rc = 0;/* End of File */
break;
@@ -473,8 +480,8 @@
count -= bytes_to_copy;
buf += bytes_to_copy;
} else {
- pr_err("%s:session id %d: short read data[%p]"
- "bytesavail[%d]bytesrequest[%d]\n", __func__,
+ pr_err("%s:session id %d: short read data[%p] bytesavail[%d]bytesrequest[%d]\n",
+ __func__,
audio->ac->session,
data, size, count);
}
@@ -529,7 +536,13 @@
rc = wait_event_interruptible(audio->write_wait,
((atomic_read(&audio->in_count) > 0) ||
(audio->stopped) ||
- (audio->wflush)));
+ (audio->wflush) || (audio->event_abort)));
+
+ if (audio->event_abort) {
+ rc = -EIO;
+ break;
+ }
+
if (rc < 0)
break;
if (audio->stopped || audio->wflush) {
@@ -554,8 +567,8 @@
&nflags);
buf += mfield_size;
/* send the EOS and return */
- pr_debug("%s:session id %d: send EOS"
- "0x%8x\n", __func__,
+ pr_debug("%s:session id %d: send EOS 0x%8x\n",
+ __func__,
audio->ac->session, nflags);
break;
}
@@ -582,8 +595,8 @@
buf += mfield_size;
count -= mfield_size;
} else {
- pr_debug("%s:session id %d: continuous"
- "buffer\n", __func__, audio->ac->session);
+ pr_debug("%s:session id %d: continuous buffer\n",
+ __func__, audio->ac->session);
}
}
xfer = (count > (audio->pcm_cfg.buffer_size)) ?
@@ -603,8 +616,8 @@
buf += xfer;
}
mutex_unlock(&audio->write_lock);
- pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x]"
- "start[0x%x]\n", __func__, audio->ac->session,
+ pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x] start[0x%x]\n",
+ __func__, audio->ac->session,
nflags, (int) buf, (int) start);
if (nflags & AUD_EOS_SET) {
rc = q6asm_cmd(audio->ac, CMD_EOS);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.h b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
index df963f9..7209724 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -30,13 +30,13 @@
struct timestamp {
unsigned long lowpart;
unsigned long highpart;
-} __attribute__ ((packed));
+} __packed;
struct meta_in {
unsigned short offset;
struct timestamp ntimestamp;
unsigned int nflags;
-} __attribute__ ((packed));
+} __packed;
struct meta_out_dsp {
u32 offset_to_frame;
@@ -45,12 +45,12 @@
u32 msw_ts;
u32 lsw_ts;
u32 nflags;
-} __attribute__ ((packed));
+} __packed;
struct meta_out {
unsigned char num_of_frames;
struct meta_out_dsp meta_out_dsp[];
-} __attribute__ ((packed));
+} __packed;
struct q6audio_in {
spinlock_t dsp_lock;
@@ -80,6 +80,7 @@
int opened;
int enabled;
int stopped;
+ int event_abort;
int feedback; /* Flag indicates whether used
in Non Tunnel mode */
int rflush;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index ad5f1b5..4827ac0 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1,6 +1,6 @@
/* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -861,10 +861,9 @@
}
param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+ param.flags = buf_node->meta_info.meta_in.nflags;
/* If no meta_info enaled, indicate no time stamp valid */
- if (audio->buf_cfg.meta_info_enable)
- param.flags = 0;
- else
+ if (!audio->buf_cfg.meta_info_enable)
param.flags = 0xFF00;
if ((buf_node != NULL) &&
@@ -1031,7 +1030,7 @@
return 0;
}
-static void audio_aio_ioport_reset(struct q6audio_aio *audio)
+void audio_aio_ioport_reset(struct q6audio_aio *audio)
{
if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
/* If fsync is in progress, make sure
@@ -1205,15 +1204,15 @@
audio, audio->ac->session);
mutex_lock(&audio->lock);
audio->stopped = 1;
- audio_aio_flush(audio);
- audio->enabled = 0;
- audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ rc = audio_aio_flush(audio);
if (rc < 0) {
pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
__func__, audio, rc);
mutex_unlock(&audio->lock);
break;
}
+ audio->enabled = 0;
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
if (audio->drv_status & ADRV_STATUS_FSYNC) {
pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
__func__, audio);
@@ -1262,8 +1261,6 @@
}
/* Flush DSP */
rc = audio_aio_flush(audio);
- /* Flush input / Output buffer in software*/
- audio_aio_ioport_reset(audio);
if (rc < 0) {
pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
__func__, audio);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index d518254..81232ad 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -1,6 +1,6 @@
/* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-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
@@ -212,6 +212,7 @@
int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
void audio_aio_async_out_flush(struct q6audio_aio *audio);
void audio_aio_async_in_flush(struct q6audio_aio *audio);
+void audio_aio_ioport_reset(struct q6audio_aio *audio);
#ifdef CONFIG_DEBUG_FS
ssize_t audio_aio_debug_open(struct inode *inode, struct file *file);
ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
diff --git a/arch/arm/mach-msm/qdsp6v2/evrc_in.c b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
index b95d659..a785266 100644
--- a/arch/arm/mach-msm/qdsp6v2/evrc_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -20,7 +20,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_qcp.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
@@ -64,8 +64,8 @@
enc_cfg->max_bit_rate, 0);
if (rc < 0) {
- pr_err("%s:session id %d: cmd evrc media format block"
- "failed\n", __func__, audio->ac->session);
+ pr_err("%s:session id %d: cmd evrc media format block failed\n",
+ __func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
@@ -74,8 +74,8 @@
audio->pcm_cfg.channel_count);
if (rc < 0) {
- pr_err("%s:session id %d: media format block"
- "failed\n", __func__, audio->ac->session);
+ pr_err("%s:session id %d: media format block failed\n",
+ __func__, audio->ac->session);
break;
}
}
@@ -86,8 +86,8 @@
audio->enabled = 1;
} else {
audio->enabled = 0;
- pr_err("%s:session id %d: Audio Start procedure failed"
- "rc=%d\n", __func__, audio->ac->session, rc);
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
@@ -102,8 +102,8 @@
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
- pr_err("%s:session id %d: Audio Stop procedure failed"
- "rc=%d\n", __func__, audio->ac->session, rc);
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
break;
}
break;
@@ -143,8 +143,8 @@
}
enc_cfg->min_bit_rate = cfg.min_bit_rate;
enc_cfg->max_bit_rate = cfg.max_bit_rate;
- pr_debug("%s:session id %d: min_bit_rate= 0x%x"
- "max_bit_rate=0x%x\n", __func__,
+ pr_debug("%s:session id %d: min_bit_rate= 0x%x max_bit_rate=0x%x\n",
+ __func__,
audio->ac->session, enc_cfg->min_bit_rate,
enc_cfg->max_bit_rate);
break;
@@ -164,16 +164,16 @@
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL) {
- pr_err("%s: Could not allocate memory for evrc"
- "driver\n", __func__);
+ pr_err("%s: Could not allocate memory for evrc driver\n",
+ __func__);
return -ENOMEM;
}
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_evrc_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
- pr_err("%s:session id %d: Could not allocate memory for aac"
- "config param\n", __func__, audio->ac->session);
+ pr_err("%s:session id %d: Could not allocate memory for aac config param\n",
+ __func__, audio->ac->session);
kfree(audio);
return -ENOMEM;
}
@@ -200,13 +200,14 @@
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
- pr_err("%s: Could not allocate memory for audio"
- "client\n", __func__);
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
@@ -239,8 +240,8 @@
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
- pr_err("%s:session id %d: TX Overflow registration"
- "failed rc=%d\n", __func__,
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__,
audio->ac->session, rc);
rc = -ENODEV;
goto fail;
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
index 5ffffd2..de4e1f0 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. 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,7 +16,7 @@
#define __Q6_AUDIO_COMMON_H__
#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM9625) \
- || defined(CONFIG_ARCH_MSM8226)
+ || defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610)
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
index 96f823f..ffd14bd 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Code Aurora Forum. 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
@@ -39,6 +39,9 @@
case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
audio_aio_cb(opcode, token, payload, audio);
break;
+ case APR_BASIC_RSP_RESULT:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
default:
pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
break;
@@ -106,6 +109,26 @@
e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
break;
+ case APR_BASIC_RSP_RESULT:
+ switch (payload[0]) {
+ case ASM_STREAM_CMD_FLUSH:
+ if (payload[1] == ADSP_EOK) {
+ pr_debug("%s: FLUSH CMD success\n", __func__);
+ audio_aio_ioport_reset(audio);
+ audio->wflush = 0;
+ audio->rflush = 0;
+ } else {
+ pr_err("%s: FLUSH CMD failed with status:%d\n",
+ __func__, payload[1]);
+ audio_aio_ioport_reset(audio);
+ audio->wflush = 0;
+ audio->rflush = 0;
+ }
+ break;
+ default:
+ pr_debug("%s: cmd%x cmd_status:%d\n",
+ __func__, payload[0], payload[1]);
+ }
default:
break;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
index 0db1ef4..7786fc0 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
@@ -51,6 +51,14 @@
pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
__func__, audio->ac->session);
break;
+ case RESET_EVENTS:
+ pr_debug("%s:received RESET EVENTS\n", __func__);
+ audio->enabled = 0;
+ audio->stopped = 1;
+ audio->event_abort = 1;
+ wake_up(&audio->read_wait);
+ wake_up(&audio->write_wait);
+ break;
default:
pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
audio->ac->session, opcode);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
index 10adc26..4610b97 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -37,6 +37,7 @@
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+ case RESET_EVENTS:
audio_aio_cb(opcode, token, payload, audio);
break;
default:
@@ -105,6 +106,13 @@
e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
break;
+ case RESET_EVENTS:
+ pr_debug("%s: Received opcode:0x%x\n", __func__, opcode);
+ audio->event_abort = 1;
+ audio->stopped = 1;
+ audio->enabled = 0;
+ wake_up(&audio->event_wait);
+ break;
default:
break;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/qcelp_in.c b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
index a48df39..3a5411e 100644
--- a/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -20,7 +20,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/msm_audio_qcp.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils.h"
@@ -64,8 +64,8 @@
enc_cfg->max_bit_rate, 0, 0);
if (rc < 0) {
- pr_err("%s:session id %d: cmd qcelp media format block"
- "failed\n", __func__, audio->ac->session);
+ pr_err("%s:session id %d: cmd qcelp media format block failed\n",
+ __func__, audio->ac->session);
break;
}
if (audio->feedback == NON_TUNNEL_MODE) {
@@ -74,8 +74,8 @@
audio->pcm_cfg.channel_count);
if (rc < 0) {
- pr_err("%s:session id %d: media format block"
- "failed\n", __func__, audio->ac->session);
+ pr_err("%s:session id %d: media format block failed\n",
+ __func__, audio->ac->session);
break;
}
}
@@ -86,8 +86,8 @@
audio->enabled = 1;
} else {
audio->enabled = 0;
- pr_err("%s:session id %d: Audio Start procedure failed"
- "rc=%d\n", __func__, audio->ac->session, rc);
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
break;
}
while (cnt++ < audio->str_cfg.buffer_count)
@@ -102,8 +102,8 @@
audio->ac->session);
rc = audio_in_disable(audio);
if (rc < 0) {
- pr_err("%s:session id %d: Audio Stop procedure failed"
- "rc=%d\n", __func__, audio->ac->session,
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session,
rc);
break;
}
@@ -141,8 +141,8 @@
}
enc_cfg->min_bit_rate = cfg.min_bit_rate;
enc_cfg->max_bit_rate = cfg.max_bit_rate;
- pr_debug("%s:session id %d: min_bit_rate= 0x%x"
- "max_bit_rate=0x%x\n", __func__,
+ pr_debug("%s:session id %d: min_bit_rate= 0x%x max_bit_rate=0x%x\n",
+ __func__,
audio->ac->session, enc_cfg->min_bit_rate,
enc_cfg->max_bit_rate);
break;
@@ -162,16 +162,16 @@
audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
if (audio == NULL) {
- pr_err("%s: Could not allocate memory for qcelp"
- "driver\n", __func__);
+ pr_err("%s: Could not allocate memory for qcelp driver\n",
+ __func__);
return -ENOMEM;
}
/* Allocate memory for encoder config param */
audio->enc_cfg = kzalloc(sizeof(struct msm_audio_qcelp_enc_config),
GFP_KERNEL);
if (audio->enc_cfg == NULL) {
- pr_err("%s:session id %d: Could not allocate memory for aac"
- "config param\n", __func__, audio->ac->session);
+ pr_err("%s:session id %d: Could not allocate memory for aac config param\n",
+ __func__, audio->ac->session);
kfree(audio);
return -ENOMEM;
}
@@ -199,13 +199,14 @@
audio->pcm_cfg.sample_rate = 8000;
audio->buf_cfg.meta_info_enable = 0x01;
audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
(void *)audio);
if (!audio->ac) {
- pr_err("%s: Could not allocate memory for audio"
- "client\n", __func__);
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
kfree(audio->enc_cfg);
kfree(audio);
return -ENOMEM;
@@ -238,8 +239,8 @@
/* register for tx overflow (valid for tunnel mode only) */
rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
if (rc < 0) {
- pr_err("%s:session id %d: TX Overflow registration"
- "failed rc=%d\n", __func__, audio->ac->session, rc);
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__, audio->ac->session, rc);
rc = -ENODEV;
goto fail;
}
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index 98a3278..4e09a9e 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -27,9 +27,231 @@
#include <mach/dal.h>
#include "smd_private.h"
-static void remote_spin_release_all_locks(uint32_t pid, int count);
-#if defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
+#define SPINLOCK_PID_APPS 1
+
+#define AUTO_MODE -1
+#define DEKKERS_MODE 1
+#define SWP_MODE 2
+#define LDREX_MODE 3
+#define SFPB_MODE 4
+
+#if defined(CONFIG_MSM_REMOTE_SPINLOCK_DEKKERS) ||\
+ defined(CONFIG_MSM_REMOTE_SPINLOCK_SWP) ||\
+ defined(CONFIG_MSM_REMOTE_SPINLOCK_LDREX) ||\
+ defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
+
+#ifdef CONFIG_MSM_REMOTE_SPINLOCK_DEKKERS
+/*
+ * Use Dekker's algorithm when LDREX/STREX and SWP are unavailable for
+ * shared memory
+ */
+#define CURRENT_MODE_INIT DEKKERS_MODE;
+#endif
+
+#ifdef CONFIG_MSM_REMOTE_SPINLOCK_SWP
+/* Use SWP-based locks when LDREX/STREX are unavailable for shared memory. */
+#define CURRENT_MODE_INIT SWP_MODE;
+#endif
+
+#ifdef CONFIG_MSM_REMOTE_SPINLOCK_LDREX
+/* Use LDREX/STREX for shared memory locking, when available */
+#define CURRENT_MODE_INIT LDREX_MODE;
+#endif
+
+#ifdef CONFIG_MSM_REMOTE_SPINLOCK_SFPB
+/* Use SFPB Hardware Mutex Registers */
+#define CURRENT_MODE_INIT SFPB_MODE;
+#endif
+
+#else
+/* Use DT info to configure with a fallback to LDREX if DT is missing */
+#define CURRENT_MODE_INIT AUTO_MODE;
+#endif
+
+static int current_mode = CURRENT_MODE_INIT;
+
+static int is_hw_lock_type;
+static DEFINE_MUTEX(ops_init_lock);
+
+struct spinlock_ops {
+ void (*lock)(raw_remote_spinlock_t *lock);
+ void (*unlock)(raw_remote_spinlock_t *lock);
+ int (*trylock)(raw_remote_spinlock_t *lock);
+ int (*release)(raw_remote_spinlock_t *lock, uint32_t pid);
+ int (*owner)(raw_remote_spinlock_t *lock);
+};
+
+static struct spinlock_ops current_ops;
+
+static int remote_spinlock_init_address(int id, _remote_spinlock_t *lock);
+
+/* dekkers implementation --------------------------------------------------- */
+#define DEK_LOCK_REQUEST 1
+#define DEK_LOCK_YIELD (!DEK_LOCK_REQUEST)
+#define DEK_YIELD_TURN_SELF 0
+static void __raw_remote_dek_spin_lock(raw_remote_spinlock_t *lock)
+{
+ lock->dek.self_lock = DEK_LOCK_REQUEST;
+
+ while (lock->dek.other_lock) {
+
+ if (lock->dek.next_yield == DEK_YIELD_TURN_SELF)
+ lock->dek.self_lock = DEK_LOCK_YIELD;
+
+ while (lock->dek.other_lock)
+ ;
+
+ lock->dek.self_lock = DEK_LOCK_REQUEST;
+ }
+ lock->dek.next_yield = DEK_YIELD_TURN_SELF;
+
+ smp_mb();
+}
+
+static int __raw_remote_dek_spin_trylock(raw_remote_spinlock_t *lock)
+{
+ lock->dek.self_lock = DEK_LOCK_REQUEST;
+
+ if (lock->dek.other_lock) {
+ lock->dek.self_lock = DEK_LOCK_YIELD;
+ return 0;
+ }
+
+ lock->dek.next_yield = DEK_YIELD_TURN_SELF;
+
+ smp_mb();
+ return 1;
+}
+
+static void __raw_remote_dek_spin_unlock(raw_remote_spinlock_t *lock)
+{
+ smp_mb();
+
+ lock->dek.self_lock = DEK_LOCK_YIELD;
+}
+
+static int __raw_remote_dek_spin_release(raw_remote_spinlock_t *lock,
+ uint32_t pid)
+{
+ return -EPERM;
+}
+
+static int __raw_remote_dek_spin_owner(raw_remote_spinlock_t *lock)
+{
+ return -EPERM;
+}
+/* end dekkers implementation ----------------------------------------------- */
+
+/* swp implementation ------------------------------------------------------- */
+static void __raw_remote_swp_spin_lock(raw_remote_spinlock_t *lock)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+"1: swp %0, %2, [%1]\n"
+" teq %0, #0\n"
+" bne 1b"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (1)
+ : "cc");
+
+ smp_mb();
+}
+
+static int __raw_remote_swp_spin_trylock(raw_remote_spinlock_t *lock)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+" swp %0, %2, [%1]\n"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (1)
+ : "cc");
+
+ if (tmp == 0) {
+ smp_mb();
+ return 1;
+ }
+ return 0;
+}
+
+static void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock)
+{
+ int lock_owner;
+
+ smp_mb();
+ lock_owner = readl_relaxed(&lock->lock);
+ if (lock_owner != SPINLOCK_PID_APPS) {
+ pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
+ __func__, lock_owner);
+ }
+
+ __asm__ __volatile__(
+" str %1, [%0]"
+ :
+ : "r" (&lock->lock), "r" (0)
+ : "cc");
+}
+/* end swp implementation --------------------------------------------------- */
+
+/* ldrex implementation ----------------------------------------------------- */
+static void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+"1: ldrex %0, [%1]\n"
+" teq %0, #0\n"
+" strexeq %0, %2, [%1]\n"
+" teqeq %0, #0\n"
+" bne 1b"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (SPINLOCK_PID_APPS)
+ : "cc");
+
+ smp_mb();
+}
+
+static int __raw_remote_ex_spin_trylock(raw_remote_spinlock_t *lock)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+" ldrex %0, [%1]\n"
+" teq %0, #0\n"
+" strexeq %0, %2, [%1]\n"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (SPINLOCK_PID_APPS)
+ : "cc");
+
+ if (tmp == 0) {
+ smp_mb();
+ return 1;
+ }
+ return 0;
+}
+
+static void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock)
+{
+ int lock_owner;
+
+ smp_mb();
+ lock_owner = readl_relaxed(&lock->lock);
+ if (lock_owner != SPINLOCK_PID_APPS) {
+ pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
+ __func__, lock_owner);
+ }
+
+ __asm__ __volatile__(
+" str %1, [%0]\n"
+ :
+ : "r" (&lock->lock), "r" (0)
+ : "cc");
+}
+/* end ldrex implementation ------------------------------------------------- */
+
+/* sfpb implementation ------------------------------------------------------ */
#define SFPB_SPINLOCK_COUNT 8
#define MSM_SFPB_MUTEX_REG_BASE 0x01200600
#define MSM_SFPB_MUTEX_REG_SIZE (33 * 4)
@@ -86,7 +308,7 @@
BUG_ON(hw_mutex_reg_base == NULL);
}
-static int remote_spinlock_init_address(int id, _remote_spinlock_t *lock)
+static int remote_spinlock_init_address_hw(int id, _remote_spinlock_t *lock)
{
/*
* Optimistic locking. Init only needs to be done once by the first
@@ -109,38 +331,133 @@
return 0;
}
-void _remote_spin_release_all(uint32_t pid)
+static void __raw_remote_sfpb_spin_lock(raw_remote_spinlock_t *lock)
{
- remote_spin_release_all_locks(pid, lock_count);
+ do {
+ writel_relaxed(SPINLOCK_PID_APPS, lock);
+ smp_mb();
+ } while (readl_relaxed(lock) != SPINLOCK_PID_APPS);
}
-#else
-#define SMEM_SPINLOCK_COUNT 8
-#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
-
-static int remote_spinlock_init_address(int id, _remote_spinlock_t *lock)
+static int __raw_remote_sfpb_spin_trylock(raw_remote_spinlock_t *lock)
{
- _remote_spinlock_t spinlock_start;
-
- if (id >= SMEM_SPINLOCK_COUNT)
- return -EINVAL;
-
- spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
- SMEM_SPINLOCK_ARRAY_SIZE);
- if (spinlock_start == NULL)
- return -ENXIO;
-
- *lock = spinlock_start + id;
-
- return 0;
+ return 1;
}
-void _remote_spin_release_all(uint32_t pid)
+static void __raw_remote_sfpb_spin_unlock(raw_remote_spinlock_t *lock)
{
- remote_spin_release_all_locks(pid, SMEM_SPINLOCK_COUNT);
+ int lock_owner;
+
+ lock_owner = readl_relaxed(lock);
+ if (lock_owner != SPINLOCK_PID_APPS) {
+ pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
+ __func__, lock_owner);
+ }
+
+ writel_relaxed(0, lock);
+ smp_mb();
+}
+/* end sfpb implementation -------------------------------------------------- */
+
+/* common spinlock API ------------------------------------------------------ */
+/**
+ * Release spinlock if it is owned by @pid.
+ *
+ * This is only to be used for situations where the processor owning
+ * the spinlock has crashed and the spinlock must be released.
+ *
+ * @lock: lock structure
+ * @pid: processor ID of processor to release
+ */
+static int __raw_remote_gen_spin_release(raw_remote_spinlock_t *lock,
+ uint32_t pid)
+{
+ int ret = 1;
+
+ if (readl_relaxed(&lock->lock) == pid) {
+ writel_relaxed(0, &lock->lock);
+ wmb();
+ ret = 0;
+ }
+ return ret;
}
-#endif
+/**
+ * Return owner of the spinlock.
+ *
+ * @lock: pointer to lock structure
+ * @returns: >= 0 owned PID; < 0 for error case
+ *
+ * Used for testing. PID's are assumed to be 31 bits or less.
+ */
+static int __raw_remote_gen_spin_owner(raw_remote_spinlock_t *lock)
+{
+ rmb();
+ return readl_relaxed(&lock->lock);
+}
+
+
+static void initialize_ops(void)
+{
+ struct device_node *node;
+
+ switch (current_mode) {
+ case DEKKERS_MODE:
+ current_ops.lock = __raw_remote_dek_spin_lock;
+ current_ops.unlock = __raw_remote_dek_spin_unlock;
+ current_ops.trylock = __raw_remote_dek_spin_trylock;
+ current_ops.release = __raw_remote_dek_spin_release;
+ current_ops.owner = __raw_remote_dek_spin_owner;
+ is_hw_lock_type = 0;
+ break;
+ case SWP_MODE:
+ current_ops.lock = __raw_remote_swp_spin_lock;
+ current_ops.unlock = __raw_remote_swp_spin_unlock;
+ current_ops.trylock = __raw_remote_swp_spin_trylock;
+ current_ops.release = __raw_remote_gen_spin_release;
+ current_ops.owner = __raw_remote_gen_spin_owner;
+ is_hw_lock_type = 0;
+ break;
+ case LDREX_MODE:
+ current_ops.lock = __raw_remote_ex_spin_lock;
+ current_ops.unlock = __raw_remote_ex_spin_unlock;
+ current_ops.trylock = __raw_remote_ex_spin_trylock;
+ current_ops.release = __raw_remote_gen_spin_release;
+ current_ops.owner = __raw_remote_gen_spin_owner;
+ is_hw_lock_type = 0;
+ break;
+ case SFPB_MODE:
+ current_ops.lock = __raw_remote_sfpb_spin_lock;
+ current_ops.unlock = __raw_remote_sfpb_spin_unlock;
+ current_ops.trylock = __raw_remote_sfpb_spin_trylock;
+ current_ops.release = __raw_remote_gen_spin_release;
+ current_ops.owner = __raw_remote_gen_spin_owner;
+ is_hw_lock_type = 1;
+ break;
+ case AUTO_MODE:
+ node = of_find_compatible_node(NULL, NULL, compatible_string);
+ if (node) {
+ current_ops.lock = __raw_remote_sfpb_spin_lock;
+ current_ops.unlock = __raw_remote_sfpb_spin_unlock;
+ current_ops.trylock = __raw_remote_sfpb_spin_trylock;
+ current_ops.release = __raw_remote_gen_spin_release;
+ current_ops.owner = __raw_remote_gen_spin_owner;
+ is_hw_lock_type = 1;
+ } else {
+ current_ops.lock = __raw_remote_ex_spin_lock;
+ current_ops.unlock = __raw_remote_ex_spin_unlock;
+ current_ops.trylock = __raw_remote_ex_spin_trylock;
+ current_ops.release = __raw_remote_gen_spin_release;
+ current_ops.owner = __raw_remote_gen_spin_owner;
+ is_hw_lock_type = 0;
+ pr_warn("Falling back to LDREX remote spinlock implementation");
+ }
+ break;
+ default:
+ BUG();
+ break;
+ }
+}
/**
* Release all spinlocks owned by @pid.
@@ -161,6 +478,11 @@
}
}
+void _remote_spin_release_all(uint32_t pid)
+{
+ remote_spin_release_all_locks(pid, lock_count);
+}
+
static int
remote_spinlock_dal_init(const char *chunk_name, _remote_spinlock_t *lock)
{
@@ -198,10 +520,54 @@
return -EINVAL;
}
+#define SMEM_SPINLOCK_COUNT 8
+#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
+
+static int remote_spinlock_init_address_smem(int id, _remote_spinlock_t *lock)
+{
+ _remote_spinlock_t spinlock_start;
+
+ if (id >= SMEM_SPINLOCK_COUNT)
+ return -EINVAL;
+
+ spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
+ SMEM_SPINLOCK_ARRAY_SIZE);
+ if (spinlock_start == NULL)
+ return -ENXIO;
+
+ *lock = spinlock_start + id;
+
+ lock_count = SMEM_SPINLOCK_COUNT;
+
+ return 0;
+}
+
+static int remote_spinlock_init_address(int id, _remote_spinlock_t *lock)
+{
+ if (is_hw_lock_type)
+ return remote_spinlock_init_address_hw(id, lock);
+ else
+ return remote_spinlock_init_address_smem(id, lock);
+}
+
int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
{
BUG_ON(id == NULL);
+ /*
+ * Optimistic locking. Init only needs to be done once by the first
+ * caller. After that, serializing inits between different callers
+ * is unnecessary. The second check after the lock ensures init
+ * wasn't previously completed by someone else before the lock could
+ * be grabbed.
+ */
+ if (!current_ops.lock) {
+ mutex_lock(&ops_init_lock);
+ if (!current_ops.lock)
+ initialize_ops();
+ mutex_unlock(&ops_init_lock);
+ }
+
if (id[0] == 'D' && id[1] == ':') {
/* DAL chunk name starts after "D:" */
return remote_spinlock_dal_init(&id[2], lock);
@@ -210,12 +576,59 @@
BUG_ON(id[3] != '\0');
return remote_spinlock_init_address((((uint8_t)id[2])-'0'),
- lock);
+ lock);
} else {
return -EINVAL;
}
}
+/*
+ * lock comes in as a pointer to a pointer to the lock location, so it must
+ * be dereferenced and casted to the right type for the actual lock
+ * implementation functions
+ */
+void _remote_spin_lock(_remote_spinlock_t *lock)
+{
+ if (unlikely(!current_ops.lock))
+ BUG();
+ current_ops.lock((raw_remote_spinlock_t *)(*lock));
+}
+EXPORT_SYMBOL(_remote_spin_lock);
+
+void _remote_spin_unlock(_remote_spinlock_t *lock)
+{
+ if (unlikely(!current_ops.unlock))
+ BUG();
+ current_ops.unlock((raw_remote_spinlock_t *)(*lock));
+}
+EXPORT_SYMBOL(_remote_spin_unlock);
+
+int _remote_spin_trylock(_remote_spinlock_t *lock)
+{
+ if (unlikely(!current_ops.trylock))
+ BUG();
+ return current_ops.trylock((raw_remote_spinlock_t *)(*lock));
+}
+EXPORT_SYMBOL(_remote_spin_trylock);
+
+int _remote_spin_release(_remote_spinlock_t *lock, uint32_t pid)
+{
+ if (unlikely(!current_ops.release))
+ BUG();
+ return current_ops.release((raw_remote_spinlock_t *)(*lock), pid);
+}
+EXPORT_SYMBOL(_remote_spin_release);
+
+int _remote_spin_owner(_remote_spinlock_t *lock)
+{
+ if (unlikely(!current_ops.owner))
+ BUG();
+ return current_ops.owner((raw_remote_spinlock_t *)(*lock));
+}
+EXPORT_SYMBOL(_remote_spin_owner);
+/* end common spinlock API -------------------------------------------------- */
+
+/* remote mutex implementation ---------------------------------------------- */
int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock)
{
BUG_ON(id == NULL);
@@ -247,3 +660,4 @@
return _remote_spin_trylock(&(lock->r_spinlock));
}
EXPORT_SYMBOL(_remote_mutex_trylock);
+/* end remote mutex implementation ------------------------------------------ */
diff --git a/arch/arm/mach-msm/rpm_master_stat.c b/arch/arm/mach-msm/rpm_master_stat.c
index 4dcf5eb..49a1039 100644
--- a/arch/arm/mach-msm/rpm_master_stat.c
+++ b/arch/arm/mach-msm/rpm_master_stat.c
@@ -130,7 +130,7 @@
if (!pdata)
return -EINVAL;
- if (!bufu || count < 0)
+ if (!bufu || count == 0)
return -EINVAL;
if ((*ppos <= pdata->phys_size)) {
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index 9a8b8ec..176c3de 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -223,7 +223,7 @@
if (!prvdata)
return -EINVAL;
- if (!bufu || count < 0)
+ if (!bufu || count == 0)
return -EINVAL;
if (prvdata->platform_data->version == 1) {
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 6d2df2a..9dc17d9 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -42,7 +42,7 @@
struct list_head out_edge_list;
struct raw_notifier_head msm_smp2p_notifier_list;
struct notifier_block *open_nb;
- uint32_t *l_smp2p_entry;
+ uint32_t __iomem *l_smp2p_entry;
};
/**
@@ -58,7 +58,7 @@
spinlock_t out_item_lock_lha1;
struct list_head list;
- struct smp2p_smem *smem_edge_out;
+ struct smp2p_smem __iomem *smem_edge_out;
enum msm_smp2p_edge_state smem_edge_state;
struct smp2p_version_if *ops_ptr;
};
@@ -76,7 +76,7 @@
* @remote_pid: Outbound processor ID.
* @in_edge_list: Adds this structure into smp2p_in_list_item::list.
* @in_notifier_list: List for notifier block for entry opening/updates.
- * @entry_val: Previous value of the entry.
+ * @prev_entry_val: Previous value of the entry.
* @entry_ptr: Points to the current value in smem item.
* @notifier_count: Counts the number of notifier registered per pid,entry.
*/
@@ -85,8 +85,8 @@
char name[SMP2P_MAX_ENTRY_NAME];
struct list_head in_edge_list;
struct raw_notifier_head in_notifier_list;
- uint32_t entry_val;
- uint32_t *entry_ptr;
+ uint32_t prev_entry_val;
+ uint32_t __iomem *entry_ptr;
uint32_t notifier_count;
};
@@ -100,7 +100,7 @@
struct smp2p_in_list_item {
spinlock_t in_item_lock_lhb1;
struct list_head list;
- struct smp2p_smem *smem_edge_in;
+ struct smp2p_smem __iomem *smem_edge_in;
uint32_t item_size;
uint32_t safe_total_entries;
};
@@ -128,8 +128,9 @@
/* common functions */
bool is_supported;
uint32_t (*negotiate_features)(uint32_t features);
- void (*find_entry)(struct smp2p_smem *item, uint32_t entries_total,
- char *name, uint32_t **entry_ptr, int *empty_spot);
+ void (*find_entry)(struct smp2p_smem __iomem *item,
+ uint32_t entries_total, char *name,
+ uint32_t **entry_ptr, int *empty_spot);
/* outbound entry functions */
int (*create_entry)(struct msm_smp2p_out *);
@@ -138,8 +139,8 @@
int (*modify_entry)(struct msm_smp2p_out *, uint32_t, uint32_t);
/* inbound entry functions */
- struct smp2p_smem *(*validate_size)(int remote_pid,
- struct smp2p_smem *, uint32_t);
+ struct smp2p_smem __iomem *(*validate_size)(int remote_pid,
+ struct smp2p_smem __iomem *, uint32_t);
};
static int smp2p_do_negotiation(int remote_pid, struct smp2p_out_list_item *p);
@@ -147,27 +148,27 @@
/* v0 (uninitialized SMEM item) interface functions */
static uint32_t smp2p_negotiate_features_v0(uint32_t features);
-static void smp2p_find_entry_v0(struct smp2p_smem *item,
+static void smp2p_find_entry_v0(struct smp2p_smem __iomem *item,
uint32_t entries_total, char *name, uint32_t **entry_ptr,
int *empty_spot);
static int smp2p_out_create_v0(struct msm_smp2p_out *);
static int smp2p_out_read_v0(struct msm_smp2p_out *, uint32_t *);
static int smp2p_out_write_v0(struct msm_smp2p_out *, uint32_t);
static int smp2p_out_modify_v0(struct msm_smp2p_out *, uint32_t, uint32_t);
-static struct smp2p_smem *smp2p_in_validate_size_v0(int remote_pid,
- struct smp2p_smem *smem_item, uint32_t size);
+static struct smp2p_smem __iomem *smp2p_in_validate_size_v0(int remote_pid,
+ struct smp2p_smem __iomem *smem_item, uint32_t size);
/* v1 interface functions */
static uint32_t smp2p_negotiate_features_v1(uint32_t features);
-static void smp2p_find_entry_v1(struct smp2p_smem *item,
+static void smp2p_find_entry_v1(struct smp2p_smem __iomem *item,
uint32_t entries_total, char *name, uint32_t **entry_ptr,
int *empty_spot);
static int smp2p_out_create_v1(struct msm_smp2p_out *);
static int smp2p_out_read_v1(struct msm_smp2p_out *, uint32_t *);
static int smp2p_out_write_v1(struct msm_smp2p_out *, uint32_t);
static int smp2p_out_modify_v1(struct msm_smp2p_out *, uint32_t, uint32_t);
-static struct smp2p_smem *smp2p_in_validate_size_v1(int remote_pid,
- struct smp2p_smem *smem_item, uint32_t size);
+static struct smp2p_smem __iomem *smp2p_in_validate_size_v1(int remote_pid,
+ struct smp2p_smem __iomem *smem_item, uint32_t size);
/* Version interface functions */
static struct smp2p_version_if version_if[] = {
@@ -251,7 +252,7 @@
*
* This is used by debugfs to print the smem items.
*/
-struct smp2p_smem *smp2p_get_in_item(int remote_pid)
+struct smp2p_smem __iomem *smp2p_get_in_item(int remote_pid)
{
void *ret = NULL;
unsigned long flags;
@@ -272,7 +273,7 @@
* @state: Edge state of the outbound SMEM item.
* @returns: Pointer to outbound (remote) SMEM item.
*/
-struct smp2p_smem *smp2p_get_out_item(int remote_pid, int *state)
+struct smp2p_smem __iomem *smp2p_get_out_item(int remote_pid, int *state)
{
void *ret = NULL;
unsigned long flags;
@@ -330,7 +331,7 @@
*/
static void *smp2p_get_local_smem_item(int remote_pid)
{
- struct smp2p_smem *item_ptr = NULL;
+ struct smp2p_smem __iomem *item_ptr = NULL;
if (remote_pid < SMP2P_REMOTE_MOCK_PROC) {
unsigned size;
@@ -422,7 +423,7 @@
* to the item is returned. If it isn't found, the first empty
* index is returned in @empty_spot.
*/
-static void smp2p_find_entry_v1(struct smp2p_smem *item,
+static void smp2p_find_entry_v1(struct smp2p_smem __iomem *item,
uint32_t entries_total, char *name, uint32_t **entry_ptr,
int *empty_spot)
{
@@ -462,7 +463,7 @@
*/
static int smp2p_out_create_v1(struct msm_smp2p_out *out_entry)
{
- struct smp2p_smem *smp2p_h_ptr;
+ struct smp2p_smem __iomem *smp2p_h_ptr;
struct smp2p_out_list_item *p_list;
uint32_t *state_entry_ptr;
uint32_t empty_spot;
@@ -531,7 +532,7 @@
*/
static int smp2p_out_read_v1(struct msm_smp2p_out *out_entry, uint32_t *data)
{
- struct smp2p_smem *smp2p_h_ptr;
+ struct smp2p_smem __iomem *smp2p_h_ptr;
uint32_t remote_pid;
if (!out_entry)
@@ -565,7 +566,7 @@
*/
static int smp2p_out_write_v1(struct msm_smp2p_out *out_entry, uint32_t data)
{
- struct smp2p_smem *smp2p_h_ptr;
+ struct smp2p_smem __iomem *smp2p_h_ptr;
uint32_t remote_pid;
if (!out_entry)
@@ -603,7 +604,7 @@
static int smp2p_out_modify_v1(struct msm_smp2p_out *out_entry,
uint32_t set_mask, uint32_t clear_mask)
{
- struct smp2p_smem *smp2p_h_ptr;
+ struct smp2p_smem __iomem *smp2p_h_ptr;
uint32_t remote_pid;
if (!out_entry)
@@ -646,19 +647,19 @@
*
* Must be called with in_item_lock_lhb1 locked.
*/
-static struct smp2p_smem *smp2p_in_validate_size_v1(int remote_pid,
- struct smp2p_smem *smem_item, uint32_t size)
+static struct smp2p_smem __iomem *smp2p_in_validate_size_v1(int remote_pid,
+ struct smp2p_smem __iomem *smem_item, uint32_t size)
{
uint32_t total_entries;
unsigned expected_size;
- struct smp2p_smem *item_ptr;
+ struct smp2p_smem __iomem *item_ptr;
struct smp2p_in_list_item *in_item;
if (remote_pid >= SMP2P_NUM_PROCS || !smem_item)
return NULL;
in_item = &in_list[remote_pid];
- item_ptr = (struct smp2p_smem *)smem_item;
+ item_ptr = (struct smp2p_smem __iomem *)smem_item;
total_entries = SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent);
if (total_entries > 0) {
@@ -716,7 +717,7 @@
*
* Entries cannot be searched for until item negotiation has been completed.
*/
-static void smp2p_find_entry_v0(struct smp2p_smem *item,
+static void smp2p_find_entry_v0(struct smp2p_smem __iomem *item,
uint32_t entries_total, char *name, uint32_t **entry_ptr,
int *empty_spot)
{
@@ -840,8 +841,8 @@
*
* Must be called with in_item_lock_lhb1 locked.
*/
-static struct smp2p_smem *smp2p_in_validate_size_v0(int remote_pid,
- struct smp2p_smem *smem_item, uint32_t size)
+static struct smp2p_smem __iomem *smp2p_in_validate_size_v0(int remote_pid,
+ struct smp2p_smem __iomem *smem_item, uint32_t size)
{
struct smp2p_in_list_item *in_item;
@@ -874,7 +875,7 @@
*
* Initializes the header as defined in the protocol specification.
*/
-void smp2p_init_header(struct smp2p_smem *header_ptr,
+void smp2p_init_header(struct smp2p_smem __iomem *header_ptr,
int local_pid, int remote_pid,
uint32_t features, uint32_t version)
{
@@ -904,7 +905,8 @@
static int smp2p_do_negotiation(int remote_pid,
struct smp2p_out_list_item *out_item)
{
- struct smp2p_smem *r_smem_ptr, *l_smem_ptr;
+ struct smp2p_smem __iomem *r_smem_ptr;
+ struct smp2p_smem __iomem *l_smem_ptr;
uint32_t r_version;
uint32_t r_feature;
uint32_t l_version, l_feature;
@@ -1331,10 +1333,10 @@
&entry_ptr, NULL);
if (entry_ptr) {
in->entry_ptr = entry_ptr;
- in->entry_val = *(entry_ptr);
+ in->prev_entry_val = readl_relaxed(entry_ptr);
- data.previous_value = in->entry_val;
- data.current_value = *(in->entry_ptr);
+ data.previous_value = in->prev_entry_val;
+ data.current_value = in->prev_entry_val;
in_notifier->notifier_call(in_notifier, SMP2P_OPEN,
(void *)&data);
}
@@ -1442,7 +1444,7 @@
struct smp2p_in *pos;
uint32_t *entry_ptr;
unsigned long flags;
- struct smp2p_smem *smem_h_ptr;
+ struct smp2p_smem __iomem *smem_h_ptr;
uint32_t curr_data;
struct msm_smp2p_update_notif data;
@@ -1456,18 +1458,7 @@
}
list_for_each_entry(pos, &in_list[pid].list, in_edge_list) {
- if (pos->entry_ptr != NULL) {
- /* entry already open */
- curr_data = *(pos->entry_ptr);
- if (curr_data != pos->entry_val) {
- data.previous_value = pos->entry_val;
- data.current_value = curr_data;
- pos->entry_val = curr_data;
- raw_notifier_call_chain(
- &pos->in_notifier_list,
- SMP2P_ENTRY_UPDATE, (void *)&data);
- }
- } else {
+ if (pos->entry_ptr == NULL) {
/* entry not open - try to open it */
out_list[pid].ops_ptr->find_entry(smem_h_ptr,
in_list[pid].safe_total_entries, pos->name,
@@ -1475,14 +1466,27 @@
if (entry_ptr) {
pos->entry_ptr = entry_ptr;
+ pos->prev_entry_val = 0;
data.previous_value = 0;
- data.current_value =
- *(entry_ptr);
+ data.current_value = readl_relaxed(entry_ptr);
raw_notifier_call_chain(
&pos->in_notifier_list,
SMP2P_OPEN, (void *)&data);
}
}
+
+ if (pos->entry_ptr != NULL) {
+ /* send update notification */
+ curr_data = readl_relaxed(pos->entry_ptr);
+ if (curr_data != pos->prev_entry_val) {
+ data.previous_value = pos->prev_entry_val;
+ data.current_value = curr_data;
+ pos->prev_entry_val = curr_data;
+ raw_notifier_call_chain(
+ &pos->in_notifier_list,
+ SMP2P_ENTRY_UPDATE, (void *)&data);
+ }
+ }
}
spin_unlock_irqrestore(&in_list[pid].in_item_lock_lhb1, flags);
}
diff --git a/arch/arm/mach-msm/smp2p_gpio_test.c b/arch/arm/mach-msm/smp2p_gpio_test.c
index 70de20a..1f6f479 100644
--- a/arch/arm/mach-msm/smp2p_gpio_test.c
+++ b/arch/arm/mach-msm/smp2p_gpio_test.c
@@ -408,6 +408,115 @@
}
/**
+ * smp2p_ut_local_gpio_in_update_open - Verify combined open/update.
+ *
+ * @s: pointer to output file
+ *
+ * If the remote side updates the SMP2P bits and sends before negotiation is
+ * complete, then the UPDATE event will have to be delayed until negotiation is
+ * complete. This should result in both the OPEN and UPDATE events coming in
+ * right after each other and the behavior should be transparent to the clients
+ * of SMP2P GPIO.
+ */
+static void smp2p_ut_local_gpio_in_update_open(struct seq_file *s)
+{
+ int failed = 0;
+ struct gpio_info *cb_info = &gpio_info[SMP2P_REMOTE_MOCK_PROC].in;
+ int id;
+ int ret;
+ int virq;
+ struct msm_smp2p_remote_mock *mock;
+
+ seq_printf(s, "Running %s\n", __func__);
+
+ cb_data_reset(cb_info);
+ do {
+ /* initialize mock edge */
+ ret = smp2p_reset_mock_edge();
+ UT_ASSERT_INT(ret, ==, 0);
+
+ mock = msm_smp2p_get_remote_mock();
+ UT_ASSERT_PTR(mock, !=, NULL);
+
+ mock->rx_interrupt_count = 0;
+ memset(&mock->remote_item, 0,
+ sizeof(struct smp2p_smem_item));
+ smp2p_init_header((struct smp2p_smem *)&mock->remote_item,
+ SMP2P_REMOTE_MOCK_PROC, SMP2P_APPS_PROC,
+ 0, 1);
+ strlcpy(mock->remote_item.entries[0].name, "smp2p",
+ SMP2P_MAX_ENTRY_NAME);
+ SMP2P_SET_ENT_VALID(
+ mock->remote_item.header.valid_total_ent, 1);
+
+ /* register for interrupts */
+ smp2p_gpio_open_test_entry("smp2p",
+ SMP2P_REMOTE_MOCK_PROC, true);
+
+ UT_ASSERT_INT(0, <, cb_info->irq_base_id);
+ for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+ virq = cb_info->irq_base_id + id;
+ UT_ASSERT_INT(0, >, (unsigned int)irq_to_desc(virq));
+ ret = request_irq(virq,
+ smp2p_gpio_irq, IRQ_TYPE_EDGE_BOTH,
+ "smp2p_test", cb_info);
+ UT_ASSERT_INT(0, ==, ret);
+ }
+ if (failed)
+ break;
+
+ /* update the state value and complete negotiation */
+ mock->remote_item.entries[0].entry = 0xDEADDEAD;
+ msm_smp2p_set_remote_mock_exists(true);
+ mock->tx_interrupt();
+
+ /* verify delayed state updates were processed */
+ for (id = 0; id < SMP2P_BITS_PER_ENTRY && !failed; ++id) {
+ virq = cb_info->irq_base_id + id;
+
+ UT_ASSERT_INT(cb_info->cb_count, >, 0);
+ if (0x1 & (0xDEADDEAD >> id)) {
+ /* rising edge should have been triggered */
+ if (!test_bit(id, cb_info->triggered_irqs)) {
+ seq_printf(s,
+ "%s:%d bit %d clear, expected set\n",
+ __func__, __LINE__, id);
+ failed = 1;
+ break;
+ }
+ } else {
+ /* edge should not have been triggered */
+ if (test_bit(id, cb_info->triggered_irqs)) {
+ seq_printf(s,
+ "%s:%d bit %d set, expected clear\n",
+ __func__, __LINE__, id);
+ failed = 1;
+ break;
+ }
+ }
+ }
+ if (failed)
+ break;
+
+ seq_printf(s, "\tOK\n");
+ } while (0);
+
+ if (failed) {
+ pr_err("%s: Failed\n", __func__);
+ seq_printf(s, "\tFailed\n");
+ }
+
+ /* unregister for interrupts */
+ if (cb_info->irq_base_id) {
+ for (id = 0; id < SMP2P_BITS_PER_ENTRY; ++id)
+ free_irq(cb_info->irq_base_id + id, cb_info);
+ }
+
+ smp2p_gpio_open_test_entry("smp2p",
+ SMP2P_REMOTE_MOCK_PROC, false);
+}
+
+/**
* smp2p_gpio_write_bits - writes value to each GPIO pin specified in mask.
*
* @gpio: gpio test structure
@@ -618,6 +727,8 @@
*/
smp2p_debug_create("ut_local_gpio_out", smp2p_ut_local_gpio_out);
smp2p_debug_create("ut_local_gpio_in", smp2p_ut_local_gpio_in);
+ smp2p_debug_create("ut_local_gpio_in_update_open",
+ smp2p_ut_local_gpio_in_update_open);
smp2p_debug_create("ut_remote_gpio_inout", smp2p_ut_remote_inout);
return 0;
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 51c995f..5bc4933 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -281,9 +281,14 @@
/* 9625 IDs */
[134] = MSM_CPU_9625,
- [152] = MSM_CPU_9625,
+ [148] = MSM_CPU_9625,
[149] = MSM_CPU_9625,
[150] = MSM_CPU_9625,
+ [151] = MSM_CPU_9625,
+ [152] = MSM_CPU_9625,
+ [173] = MSM_CPU_9625,
+ [174] = MSM_CPU_9625,
+ [175] = MSM_CPU_9625,
/* 8960AB IDs */
[138] = MSM_CPU_8960AB,
@@ -320,6 +325,8 @@
[169] = MSM_CPU_8625Q,
[170] = MSM_CPU_8625Q,
+ /* 8064AA IDs */
+ [172] = MSM_CPU_8064AA,
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -814,67 +821,6 @@
return 0;
}
-static int __init socinfo_init_sysdev(void)
-{
- int err;
-
- if (!socinfo) {
- pr_err("%s: No socinfo found!\n", __func__);
- return -ENODEV;
- }
-
- err = sysdev_class_register(&soc_sysdev_class);
- if (err) {
- pr_err("%s: sysdev_class_register fail (%d)\n",
- __func__, err);
- return err;
- }
- err = sysdev_register(&soc_sys_device);
- if (err) {
- pr_err("%s: sysdev_register fail (%d)\n",
- __func__, err);
- return err;
- }
- socinfo_create_files(&soc_sys_device, socinfo_v1_files,
- ARRAY_SIZE(socinfo_v1_files));
- if (socinfo->v1.format < 2)
- return err;
- socinfo_create_files(&soc_sys_device, socinfo_v2_files,
- ARRAY_SIZE(socinfo_v2_files));
-
- if (socinfo->v1.format < 3)
- return err;
-
- socinfo_create_files(&soc_sys_device, socinfo_v3_files,
- ARRAY_SIZE(socinfo_v3_files));
-
- if (socinfo->v1.format < 4)
- return err;
-
- socinfo_create_files(&soc_sys_device, socinfo_v4_files,
- ARRAY_SIZE(socinfo_v4_files));
-
- if (socinfo->v1.format < 5)
- return err;
-
- socinfo_create_files(&soc_sys_device, socinfo_v5_files,
- ARRAY_SIZE(socinfo_v5_files));
-
- if (socinfo->v1.format < 6)
- return err;
-
- socinfo_create_files(&soc_sys_device, socinfo_v6_files,
- ARRAY_SIZE(socinfo_v6_files));
-
- if (socinfo->v1.format < 7)
- return err;
-
- return socinfo_create_files(&soc_sys_device, socinfo_v7_files,
- ARRAY_SIZE(socinfo_v7_files));
-}
-
-arch_initcall(socinfo_init_sysdev);
-
static void * __init setup_dummy_socinfo(void)
{
if (machine_is_msm8960_cdp())
@@ -964,6 +910,88 @@
}
+static int __init socinfo_init_sysdev(void)
+{
+ int err;
+ struct device *msm_soc_device;
+ struct soc_device *soc_dev;
+ struct soc_device_attribute *soc_dev_attr;
+
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return -ENODEV;
+ }
+
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr) {
+ pr_err("%s: Soc Device alloc failed!\n", __func__);
+ return -ENOMEM;
+ }
+
+ soc_info_populate(soc_dev_attr);
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR_OR_NULL(soc_dev)) {
+ kfree(soc_dev_attr);
+ pr_err("%s: Soc device register failed\n", __func__);
+ return -EIO;
+ }
+
+ msm_soc_device = soc_device_to_device(soc_dev);
+ populate_soc_sysfs_files(msm_soc_device);
+ err = sysdev_class_register(&soc_sysdev_class);
+ if (err) {
+ pr_err("%s: sysdev_class_register fail (%d)\n",
+ __func__, err);
+ return err;
+ }
+ err = sysdev_register(&soc_sys_device);
+ if (err) {
+ pr_err("%s: sysdev_register fail (%d)\n",
+ __func__, err);
+ return err;
+ }
+ socinfo_create_files(&soc_sys_device, socinfo_v1_files,
+ ARRAY_SIZE(socinfo_v1_files));
+ if (socinfo->v1.format < 2)
+ return err;
+ socinfo_create_files(&soc_sys_device, socinfo_v2_files,
+ ARRAY_SIZE(socinfo_v2_files));
+
+ if (socinfo->v1.format < 3)
+ return err;
+
+ socinfo_create_files(&soc_sys_device, socinfo_v3_files,
+ ARRAY_SIZE(socinfo_v3_files));
+
+ if (socinfo->v1.format < 4)
+ return err;
+
+ socinfo_create_files(&soc_sys_device, socinfo_v4_files,
+ ARRAY_SIZE(socinfo_v4_files));
+
+ if (socinfo->v1.format < 5)
+ return err;
+
+ socinfo_create_files(&soc_sys_device, socinfo_v5_files,
+ ARRAY_SIZE(socinfo_v5_files));
+
+ if (socinfo->v1.format < 6)
+ return err;
+
+ socinfo_create_files(&soc_sys_device, socinfo_v6_files,
+ ARRAY_SIZE(socinfo_v6_files));
+
+ if (socinfo->v1.format < 7)
+ return err;
+
+ socinfo_create_files(&soc_sys_device, socinfo_v7_files,
+ ARRAY_SIZE(socinfo_v7_files));
+
+ return 0;
+}
+
+arch_initcall(socinfo_init_sysdev);
+
static void socinfo_print(void)
{
switch (socinfo->v1.format) {
@@ -1043,12 +1071,8 @@
}
}
-struct device * __init socinfo_init(void)
+int __init socinfo_init(void)
{
- struct device *msm_soc_device;
- struct soc_device *soc_dev;
- struct soc_device_attribute *soc_dev_attr;
-
socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
if (!socinfo)
@@ -1089,21 +1113,8 @@
cur_cpu = cpu_of_id[socinfo->v1.id];
socinfo_print();
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- return ERR_PTR(-ENOMEM);
- soc_info_populate(soc_dev_attr);
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR_OR_NULL(soc_dev)) {
- kfree(soc_dev_attr);
- return ERR_PTR(-EIO);
- }
-
- msm_soc_device = soc_device_to_device(soc_dev);
- populate_soc_sysfs_files(msm_soc_device);
-
- return msm_soc_device;
+ return 0;
}
const int get_core_count(void)
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 620aa1d..e395dec 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -358,11 +358,13 @@
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
{
uint32_t timeout_us, new_level;
- bool avs_enabled = msm_spm_drv_is_avs_enabled(dev);
+ bool avs_enabled;
if (!dev)
return -EINVAL;
+ avs_enabled = msm_spm_drv_is_avs_enabled(dev);
+
if (!msm_spm_pmic_arb_present(dev))
return -ENOSYS;
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
index dbc8100..031b2dc 100644
--- a/arch/arm/mach-msm/test-lpm.c
+++ b/arch/arm/mach-msm/test-lpm.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
@@ -26,6 +26,9 @@
#if defined(CONFIG_MSM_RPM)
#include "rpm_resources.h"
#endif
+#if defined(CONFIG_MSM_RPM_SMD)
+#include "lpm_resources.h"
+#endif
#include "timer.h"
#include "test-lpm.h"
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 1f6bd1d..e734ece 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.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
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/of_coresight.h>
#include <linux/coresight.h>
@@ -74,6 +75,7 @@
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
+ uint32_t blksize;
};
static struct csr_drvdata *csrdrvdata;
@@ -86,7 +88,7 @@
CSR_UNLOCK(drvdata);
usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
- usbbamctrl = (usbbamctrl & ~0x3) | BLKSIZE_2048;
+ usbbamctrl = (usbbamctrl & ~0x3) | drvdata->blksize;
csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
@@ -119,6 +121,7 @@
static int __devinit csr_probe(struct platform_device *pdev)
{
+ int ret;
struct device *dev = &pdev->dev;
struct coresight_platform_data *pdata;
struct csr_drvdata *drvdata;
@@ -148,6 +151,13 @@
if (!drvdata->base)
return -ENOMEM;
+ if (pdev->dev.of_node) {
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,blk-size",
+ &drvdata->blksize);
+ if (ret)
+ drvdata->blksize = BLKSIZE_256;
+ }
+
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index b569aed..521d9ec 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -209,6 +209,8 @@
int cpu;
uint8_t arch;
bool enable;
+ bool sticky_enable;
+ bool boot_enable;
bool os_unlock;
uint8_t nr_addr_cmp;
uint8_t nr_cntr;
@@ -256,6 +258,7 @@
bool pcsave_enable;
bool pcsave_sticky_enable;
bool pcsave_boot_enable;
+ bool round_robin;
};
static struct etm_drvdata *etmdrvdata[NR_CPUS];
@@ -500,7 +503,6 @@
if (ret)
goto err_clk;
- get_online_cpus();
spin_lock(&drvdata->spinlock);
/*
@@ -511,9 +513,9 @@
if (ret)
goto err;
drvdata->enable = true;
+ drvdata->sticky_enable = true;
spin_unlock(&drvdata->spinlock);
- put_online_cpus();
wake_unlock(&drvdata->wake_lock);
@@ -521,7 +523,6 @@
return 0;
err:
spin_unlock(&drvdata->spinlock);
- put_online_cpus();
clk_disable_unprepare(drvdata->clk);
err_clk:
wake_unlock(&drvdata->wake_lock);
@@ -551,6 +552,12 @@
wake_lock(&drvdata->wake_lock);
+ /*
+ * Taking hotplug lock here protects from clocks getting disabled
+ * with tracing being left on (crash scenario) if user disable occurs
+ * after cpu online mask indicates the cpu is offline but before the
+ * DYING hotplug callback is serviced by the ETM driver.
+ */
get_online_cpus();
spin_lock(&drvdata->spinlock);
@@ -1720,7 +1727,7 @@
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
-static int ____etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
+static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
{
int ret = 0;
@@ -1760,17 +1767,6 @@
return ret;
}
-static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
-{
- int ret;
-
- get_online_cpus();
- ret = ____etm_store_pcsave(drvdata, val);
- put_online_cpus();
-
- return ret;
-}
-
static ssize_t etm_store_pcsave(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
@@ -1842,37 +1838,40 @@
{
unsigned int cpu = (unsigned long)hcpu;
+ if (!etmdrvdata[cpu])
+ goto out;
+
switch (action & (~CPU_TASKS_FROZEN)) {
case CPU_STARTING:
- if (etmdrvdata[cpu] && !etmdrvdata[cpu]->os_unlock) {
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ spin_lock(&etmdrvdata[cpu]->spinlock);
+ if (!etmdrvdata[cpu]->os_unlock) {
etm_os_unlock(etmdrvdata[cpu]);
etmdrvdata[cpu]->os_unlock = true;
- spin_unlock(&etmdrvdata[cpu]->spinlock);
}
- if (etmdrvdata[cpu] && etmdrvdata[cpu]->enable) {
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ if (etmdrvdata[cpu]->enable && etmdrvdata[cpu]->round_robin)
__etm_enable(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- }
+ spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
case CPU_ONLINE:
- if (etmdrvdata[cpu] && etmdrvdata[cpu]->pcsave_boot_enable &&
- !etmdrvdata[cpu]->pcsave_sticky_enable) {
- ____etm_store_pcsave(etmdrvdata[cpu], 1);
- }
+ if (etmdrvdata[cpu]->boot_enable &&
+ !etmdrvdata[cpu]->sticky_enable)
+ coresight_enable(etmdrvdata[cpu]->csdev);
+
+ if (etmdrvdata[cpu]->pcsave_boot_enable &&
+ !etmdrvdata[cpu]->pcsave_sticky_enable)
+ __etm_store_pcsave(etmdrvdata[cpu], 1);
break;
case CPU_DYING:
- if (etmdrvdata[cpu] && etmdrvdata[cpu]->enable) {
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ spin_lock(&etmdrvdata[cpu]->spinlock);
+ if (etmdrvdata[cpu]->enable && etmdrvdata[cpu]->round_robin)
__etm_disable(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- }
+ spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
}
+out:
return NOTIFY_OK;
}
@@ -2108,6 +2107,10 @@
clk_disable_unprepare(drvdata->clk);
+ if (pdev->dev.of_node)
+ drvdata->round_robin = of_property_read_bool(pdev->dev.of_node,
+ "qcom,round-robin");
+
baddr = devm_kzalloc(dev, PAGE_SIZE + reg_size, GFP_KERNEL);
if (baddr) {
*(uint32_t *)(baddr + ETM_REG_DUMP_VER_OFF) = ETM_REG_DUMP_VER;
@@ -2153,8 +2156,10 @@
dev_info(dev, "ETM initialized\n");
- if (boot_enable)
+ if (boot_enable) {
coresight_enable(drvdata->csdev);
+ drvdata->boot_enable = true;
+ }
if (drvdata->pcsave_impl && boot_pcsave_enable) {
__etm_store_pcsave(drvdata, 1);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4eac9cb..ab9e83a 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -895,10 +895,7 @@
len = ALIGN(len, pce_dev->ce_sps.ce_burst_size);
while (len > 0) {
if (len > SPS_MAX_PKT_SIZE) {
- if ((len % SPS_MAX_PKT_SIZE) > 0)
- data_cnt = (len % SPS_MAX_PKT_SIZE);
- else
- data_cnt = SPS_MAX_PKT_SIZE;
+ data_cnt = SPS_MAX_PKT_SIZE;
iovec->size = data_cnt;
iovec->addr = addr;
iovec->flags = 0;
@@ -1251,8 +1248,27 @@
notify->data.transfer.iovec.addr,
notify->data.transfer.iovec.size,
notify->data.transfer.iovec.flags);
- /* done */
- _aead_complete(pce_dev);
+
+ if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+ /* done */
+ _aead_complete(pce_dev);
+ } else {
+ int rc = 0;
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+ pce_dev->ce_sps.out_transfer.iovec_count = 0;
+ _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+ CRYPTO_RESULT_DUMP_SIZE,
+ &pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+ rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
+ &pce_dev->ce_sps.out_transfer);
+ if (rc) {
+ pr_err("sps_xfr() fail (producer pipe=0x%x) rc = %d,",
+ (u32)pce_dev->ce_sps.producer.pipe, rc);
+ }
+ }
};
static void _aead_sps_consumer_callback(struct sps_event_notify *notify)
@@ -1307,8 +1323,27 @@
notify->data.transfer.iovec.addr,
notify->data.transfer.iovec.size,
notify->data.transfer.iovec.flags);
- /* done */
- _ablk_cipher_complete(pce_dev);
+
+ if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+ /* done */
+ _ablk_cipher_complete(pce_dev);
+ } else {
+ int rc = 0;
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+ pce_dev->ce_sps.out_transfer.iovec_count = 0;
+ _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+ CRYPTO_RESULT_DUMP_SIZE,
+ &pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+ rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
+ &pce_dev->ce_sps.out_transfer);
+ if (rc) {
+ pr_err("sps_xfr() fail (producer pipe=0x%x) rc = %d,",
+ (u32)pce_dev->ce_sps.producer.pipe, rc);
+ }
+ }
};
static void _ablk_cipher_sps_consumer_callback(struct sps_event_notify *notify)
@@ -2258,7 +2293,6 @@
pr_err("Producer callback registration failed rc = %d\n", rc);
goto bad;
}
-
/* Register callback event for EOT (End of transfer) event. */
pce_dev->ce_sps.consumer.event.callback = _aead_sps_consumer_callback;
rc = sps_register_event(pce_dev->ce_sps.consumer.pipe,
@@ -2283,11 +2317,21 @@
_qce_sps_add_sg_data(pce_dev, areq->dst, out_len +
areq->assoclen + hw_pad_out,
&pce_dev->ce_sps.out_transfer);
- _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+ if (totallen_in > SPS_MAX_PKT_SIZE) {
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
+ pce_dev->ce_sps.producer.event.options =
+ SPS_O_DESC_DONE;
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+ } else {
+ _qce_sps_add_data(GET_PHYS_ADDR(
+ pce_dev->ce_sps.result_dump),
CRYPTO_RESULT_DUMP_SIZE,
- &pce_dev->ce_sps.out_transfer);
- _qce_set_flag(&pce_dev->ce_sps.out_transfer,
- SPS_IOVEC_FLAG_INT);
+ &pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+ }
} else {
_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen,
&pce_dev->ce_sps.in_transfer);
@@ -2307,11 +2351,21 @@
/* Pass through to ignore hw_pad (padding of the MAC data) */
_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
hw_pad_out, &pce_dev->ce_sps.out_transfer);
-
- _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
- CRYPTO_RESULT_DUMP_SIZE, &pce_dev->ce_sps.out_transfer);
- _qce_set_flag(&pce_dev->ce_sps.out_transfer,
- SPS_IOVEC_FLAG_INT);
+ if (totallen_in > SPS_MAX_PKT_SIZE) {
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
+ pce_dev->ce_sps.producer.event.options =
+ SPS_O_DESC_DONE;
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+ } else {
+ _qce_sps_add_data(
+ GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+ CRYPTO_RESULT_DUMP_SIZE,
+ &pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+ }
}
rc = _qce_sps_transfer(pce_dev);
if (rc)
@@ -2395,7 +2449,6 @@
pr_err("Producer callback registration failed rc = %d\n", rc);
goto bad;
}
-
/* Register callback event for EOT (End of transfer) event. */
pce_dev->ce_sps.consumer.event.callback =
_ablk_cipher_sps_consumer_callback;
@@ -2417,10 +2470,19 @@
_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes,
&pce_dev->ce_sps.out_transfer);
- _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+ if (areq->nbytes > SPS_MAX_PKT_SIZE) {
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
+ pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE;
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+ } else {
+ pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+ _qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
CRYPTO_RESULT_DUMP_SIZE,
&pce_dev->ce_sps.out_transfer);
- _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
+ }
rc = _qce_sps_transfer(pce_dev);
if (rc)
goto bad;
diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h
index 7a7aacc..8533636 100644
--- a/drivers/crypto/msm/qce50.h
+++ b/drivers/crypto/msm/qce50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -36,7 +36,7 @@
/* QCE max number of descriptor in a descriptor list */
#define QCE_MAX_NUM_DESC 128
-#define SPS_MAX_PKT_SIZE (16 * 1024)
+#define SPS_MAX_PKT_SIZE (32 * 1024 - 64)
/* State of consumer/producer Pipe */
enum qce_pipe_st_enum {
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index d77311d..0fb924f 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -59,77 +59,78 @@
#define CRYPTO_ENCR_XTS_KEY6_REG 0x1D038
#define CRYPTO_ENCR_XTS_KEY7_REG 0x1D03C
-#define CRYPTO_ENCR_PIP0_KEY0_REG 0x1E000
-#define CRYPTO_ENCR_PIP0_KEY1_REG 0x1E004
-#define CRYPTO_ENCR_PIP0_KEY2_REG 0x1E008
-#define CRYPTO_ENCR_PIP0_KEY3_REG 0x1E00C
-#define CRYPTO_ENCR_PIP0_KEY4_REG 0x1E010
-#define CRYPTO_ENCR_PIP0_KEY5_REG 0x1E004
-#define CRYPTO_ENCR_PIP0_KEY6_REG 0x1E008
-#define CRYPTO_ENCR_PIP0_KEY7_REG 0x1E00C
+#define CRYPTO_ENCR_PIPE0_KEY0_REG 0x1E000
+#define CRYPTO_ENCR_PIPE0_KEY1_REG 0x1E004
+#define CRYPTO_ENCR_PIPE0_KEY2_REG 0x1E008
+#define CRYPTO_ENCR_PIPE0_KEY3_REG 0x1E00C
+#define CRYPTO_ENCR_PIPE0_KEY4_REG 0x1E010
+#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E004
+#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E008
+#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E00C
-#define CRYPTO_ENCR_PIP1_KEY0_REG 0x1E000
-#define CRYPTO_ENCR_PIP1_KEY1_REG 0x1E004
-#define CRYPTO_ENCR_PIP1_KEY2_REG 0x1E008
-#define CRYPTO_ENCR_PIP1_KEY3_REG 0x1E00C
-#define CRYPTO_ENCR_PIP1_KEY4_REG 0x1E010
-#define CRYPTO_ENCR_PIP1_KEY5_REG 0x1E014
-#define CRYPTO_ENCR_PIP1_KEY6_REG 0x1E018
-#define CRYPTO_ENCR_PIP1_KEY7_REG 0x1E01C
+#define CRYPTO_ENCR_PIPE1_KEY0_REG 0x1E020
+#define CRYPTO_ENCR_PIPE1_KEY1_REG 0x1E024
+#define CRYPTO_ENCR_PIPE1_KEY2_REG 0x1E028
+#define CRYPTO_ENCR_PIPE1_KEY3_REG 0x1E02C
+#define CRYPTO_ENCR_PIPE1_KEY4_REG 0x1E030
+#define CRYPTO_ENCR_PIPE1_KEY5_REG 0x1E034
+#define CRYPTO_ENCR_PIPE1_KEY6_REG 0x1E038
+#define CRYPTO_ENCR_PIPE1_KEY7_REG 0x1E03C
-#define CRYPTO_ENCR_PIP2_KEY0_REG 0x1E020
-#define CRYPTO_ENCR_PIP2_KEY1_REG 0x1E024
-#define CRYPTO_ENCR_PIP2_KEY2_REG 0x1E028
-#define CRYPTO_ENCR_PIP2_KEY3_REG 0x1E02C
-#define CRYPTO_ENCR_PIP2_KEY4_REG 0x1E030
-#define CRYPTO_ENCR_PIP2_KEY5_REG 0x1E034
-#define CRYPTO_ENCR_PIP2_KEY6_REG 0x1E038
-#define CRYPTO_ENCR_PIP2_KEY7_REG 0x1E03C
+#define CRYPTO_ENCR_PIPE2_KEY0_REG 0x1E040
+#define CRYPTO_ENCR_PIPE2_KEY1_REG 0x1E044
+#define CRYPTO_ENCR_PIPE2_KEY2_REG 0x1E048
+#define CRYPTO_ENCR_PIPE2_KEY3_REG 0x1E04C
+#define CRYPTO_ENCR_PIPE2_KEY4_REG 0x1E050
+#define CRYPTO_ENCR_PIPE2_KEY5_REG 0x1E054
+#define CRYPTO_ENCR_PIPE2_KEY6_REG 0x1E058
+#define CRYPTO_ENCR_PIPE2_KEY7_REG 0x1E05C
-#define CRYPTO_ENCR_PIP3_KEY0_REG 0x1E040
-#define CRYPTO_ENCR_PIP3_KEY1_REG 0x1E044
-#define CRYPTO_ENCR_PIP3_KEY2_REG 0x1E048
-#define CRYPTO_ENCR_PIP3_KEY3_REG 0x1E04C
-#define CRYPTO_ENCR_PIP3_KEY4_REG 0x1E050
-#define CRYPTO_ENCR_PIP3_KEY5_REG 0x1E054
-#define CRYPTO_ENCR_PIP3_KEY6_REG 0x1E058
-#define CRYPTO_ENCR_PIP3_KEY7_REG 0x1E05C
+#define CRYPTO_ENCR_PIPE3_KEY0_REG 0x1E060
+#define CRYPTO_ENCR_PIPE3_KEY1_REG 0x1E064
+#define CRYPTO_ENCR_PIPE3_KEY2_REG 0x1E068
+#define CRYPTO_ENCR_PIPE3_KEY3_REG 0x1E06C
+#define CRYPTO_ENCR_PIPE3_KEY4_REG 0x1E070
+#define CRYPTO_ENCR_PIPE3_KEY5_REG 0x1E074
+#define CRYPTO_ENCR_PIPE3_KEY6_REG 0x1E078
+#define CRYPTO_ENCR_PIPE3_KEY7_REG 0x1E07C
-#define CRYPTO_ENCR_PIP0_XTS_KEY0_REG 0x1E200
-#define CRYPTO_ENCR_PIP0_XTS_KEY1_REG 0x1E204
-#define CRYPTO_ENCR_PIP0_XTS_KEY2_REG 0x1E208
-#define CRYPTO_ENCR_PIP0_XTS_KEY3_REG 0x1E20C
-#define CRYPTO_ENCR_PIP0_XTS_KEY4_REG 0x1E210
-#define CRYPTO_ENCR_PIP0_XTS_KEY5_REG 0x1E214
-#define CRYPTO_ENCR_PIP0_XTS_KEY6_REG 0x1E218
-#define CRYPTO_ENCR_PIP0_XTS_KEY7_REG 0x1E21C
-#define CRYPTO_ENCR_PIP1_XTS_KEY0_REG 0x1E220
-#define CRYPTO_ENCR_PIP1_XTS_KEY1_REG 0x1E224
-#define CRYPTO_ENCR_PIP1_XTS_KEY2_REG 0x1E228
-#define CRYPTO_ENCR_PIP1_XTS_KEY3_REG 0x1E22C
-#define CRYPTO_ENCR_PIP1_XTS_KEY4_REG 0x1E230
-#define CRYPTO_ENCR_PIP1_XTS_KEY5_REG 0x1E234
-#define CRYPTO_ENCR_PIP1_XTS_KEY6_REG 0x1E238
-#define CRYPTO_ENCR_PIP1_XTS_KEY7_REG 0x1E23C
+#define CRYPTO_ENCR_PIPE0_XTS_KEY0_REG 0x1E200
+#define CRYPTO_ENCR_PIPE0_XTS_KEY1_REG 0x1E204
+#define CRYPTO_ENCR_PIPE0_XTS_KEY2_REG 0x1E208
+#define CRYPTO_ENCR_PIPE0_XTS_KEY3_REG 0x1E20C
+#define CRYPTO_ENCR_PIPE0_XTS_KEY4_REG 0x1E210
+#define CRYPTO_ENCR_PIPE0_XTS_KEY5_REG 0x1E214
+#define CRYPTO_ENCR_PIPE0_XTS_KEY6_REG 0x1E218
+#define CRYPTO_ENCR_PIPE0_XTS_KEY7_REG 0x1E21C
-#define CRYPTO_ENCR_PIP2_XTS_KEY0_REG 0x1E240
-#define CRYPTO_ENCR_PIP2_XTS_KEY1_REG 0x1E244
-#define CRYPTO_ENCR_PIP2_XTS_KEY2_REG 0x1E248
-#define CRYPTO_ENCR_PIP2_XTS_KEY3_REG 0x1E24C
-#define CRYPTO_ENCR_PIP2_XTS_KEY4_REG 0x1E250
-#define CRYPTO_ENCR_PIP2_XTS_KEY5_REG 0x1E254
-#define CRYPTO_ENCR_PIP2_XTS_KEY6_REG 0x1E258
-#define CRYPTO_ENCR_PIP2_XTS_KEY7_REG 0x1E25C
+#define CRYPTO_ENCR_PIPE1_XTS_KEY0_REG 0x1E220
+#define CRYPTO_ENCR_PIPE1_XTS_KEY1_REG 0x1E224
+#define CRYPTO_ENCR_PIPE1_XTS_KEY2_REG 0x1E228
+#define CRYPTO_ENCR_PIPE1_XTS_KEY3_REG 0x1E22C
+#define CRYPTO_ENCR_PIPE1_XTS_KEY4_REG 0x1E230
+#define CRYPTO_ENCR_PIPE1_XTS_KEY5_REG 0x1E234
+#define CRYPTO_ENCR_PIPE1_XTS_KEY6_REG 0x1E238
+#define CRYPTO_ENCR_PIPE1_XTS_KEY7_REG 0x1E23C
-#define CRYPTO_ENCR_PIP3_XTS_KEY0_REG 0x1E260
-#define CRYPTO_ENCR_PIP3_XTS_KEY1_REG 0x1E264
-#define CRYPTO_ENCR_PIP3_XTS_KEY2_REG 0x1E268
-#define CRYPTO_ENCR_PIP3_XTS_KEY3_REG 0x1E26C
-#define CRYPTO_ENCR_PIP3_XTS_KEY4_REG 0x1E270
-#define CRYPTO_ENCR_PIP3_XTS_KEY5_REG 0x1E274
-#define CRYPTO_ENCR_PIP3_XTS_KEY6_REG 0x1E278
-#define CRYPTO_ENCR_PIP3_XTS_KEY7_REG 0x1E27C
+#define CRYPTO_ENCR_PIPE2_XTS_KEY0_REG 0x1E240
+#define CRYPTO_ENCR_PIPE2_XTS_KEY1_REG 0x1E244
+#define CRYPTO_ENCR_PIPE2_XTS_KEY2_REG 0x1E248
+#define CRYPTO_ENCR_PIPE2_XTS_KEY3_REG 0x1E24C
+#define CRYPTO_ENCR_PIPE2_XTS_KEY4_REG 0x1E250
+#define CRYPTO_ENCR_PIPE2_XTS_KEY5_REG 0x1E254
+#define CRYPTO_ENCR_PIPE2_XTS_KEY6_REG 0x1E258
+#define CRYPTO_ENCR_PIPE2_XTS_KEY7_REG 0x1E25C
+
+#define CRYPTO_ENCR_PIPE3_XTS_KEY0_REG 0x1E260
+#define CRYPTO_ENCR_PIPE3_XTS_KEY1_REG 0x1E264
+#define CRYPTO_ENCR_PIPE3_XTS_KEY2_REG 0x1E268
+#define CRYPTO_ENCR_PIPE3_XTS_KEY3_REG 0x1E26C
+#define CRYPTO_ENCR_PIPE3_XTS_KEY4_REG 0x1E270
+#define CRYPTO_ENCR_PIPE3_XTS_KEY5_REG 0x1E274
+#define CRYPTO_ENCR_PIPE3_XTS_KEY6_REG 0x1E278
+#define CRYPTO_ENCR_PIPE3_XTS_KEY7_REG 0x1E27C
#define CRYPTO_CNTR0_IV0_REG 0x1A20C
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 3332fc5..39f5452 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -345,8 +345,10 @@
mb();
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
- if (msm_gpio_irq_extn.irq_set_type)
- msm_gpio_irq_extn.irq_set_type(d, flow_type);
+ if ((flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) {
+ if (msm_gpio_irq_extn.irq_set_type)
+ msm_gpio_irq_extn.irq_set_type(d, flow_type);
+ }
return 0;
}
diff --git a/drivers/gpio/pm8xxx-gpio.c b/drivers/gpio/pm8xxx-gpio.c
index cb874e8..92f697f 100644
--- a/drivers/gpio/pm8xxx-gpio.c
+++ b/drivers/gpio/pm8xxx-gpio.c
@@ -1,7 +1,7 @@
/*
* Qualcomm PMIC8XXX GPIO driver
*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, Code Aurora Forum. 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
@@ -85,9 +85,6 @@
{
int mode;
- if (gpio >= pm_gpio_chip->gpio_chip.ngpio || pm_gpio_chip == NULL)
- return -EINVAL;
-
/* Get gpio value from config bank 1 if output gpio.
Get gpio value from IRQ RT status register for all other gpio modes.
*/
@@ -107,9 +104,6 @@
u8 bank1;
unsigned long flags;
- if (gpio >= pm_gpio_chip->gpio_chip.ngpio || pm_gpio_chip == NULL)
- return -EINVAL;
-
spin_lock_irqsave(&pm_gpio_chip->pm_lock, flags);
bank1 = PM_GPIO_WRITE
| (pm_gpio_chip->bank1[gpio] & ~PM_GPIO_OUT_INVERT);
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 90f14e6..4a47c59 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -67,6 +67,10 @@
#define A3XX_RBBM_INT_0_STATUS 0x064
#define A3XX_RBBM_PERFCTR_CTL 0x80
#define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_SP_5_LO 0xDC
+#define A3XX_RBBM_PERFCTR_SP_5_HI 0xDD
+#define A3XX_RBBM_PERFCTR_SP_6_LO 0xDE
+#define A3XX_RBBM_PERFCTR_SP_6_HI 0xDF
#define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
#define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
#define A3XX_RBBM_RBBM_CTL 0x100
@@ -164,6 +168,8 @@
#define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
#define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
#define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER5_SELECT 0xEC9
+#define A3XX_SP_PERFCOUNTER6_SELECT 0xECA
#define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
@@ -539,5 +545,8 @@
/* COUNTABLE FOR SP PERFCOUNTER */
#define SP_FS_FULL_ALU_INSTRUCTIONS 0x0E
+#define SP_ALU_ACTIVE_CYCLES 0x1D
+#define SP0_ICL1_MISSES 0x1A
+#define SP_FS_CFLOW_INSTRUCTIONS 0x0C
#endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 612e34a..5c98599 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -130,6 +130,10 @@
REG_CP_IB2_BASE,
REG_CP_IB2_BUFSZ,
0,
+ 0,
+ 0,
+ 0,
+ 0,
0
};
@@ -304,6 +308,8 @@
num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = idr_find(&device->context_idr, context_id);
+ if (context == NULL)
+ return;
adreno_ctx = context->devctxt;
if (kgsl_mmu_enable_clk(&device->mmu,
@@ -454,6 +460,8 @@
*/
if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) {
context = idr_find(&device->context_idr, context_id);
+ if (context == NULL)
+ return;
adreno_ctx = context->devctxt;
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -973,9 +981,17 @@
goto err;
}
- if (adreno_of_read_property(child, "qcom,iommu-ctx-sids",
- &ctxs[ctx_index].ctx_id))
+ ret = of_property_read_u32_array(child, "reg", reg_val, 2);
+ if (ret) {
+ KGSL_CORE_ERR("Unable to read KGSL IOMMU 'reg'\n");
goto err;
+ }
+ if (msm_soc_version_supports_iommu_v1())
+ ctxs[ctx_index].ctx_id = (reg_val[0] -
+ data->physstart) >> KGSL_IOMMU_CTX_SHIFT;
+ else
+ ctxs[ctx_index].ctx_id = ((reg_val[0] -
+ data->physstart) >> KGSL_IOMMU_CTX_SHIFT) - 8;
ctx_index++;
}
@@ -1263,6 +1279,10 @@
if (adreno_is_a3xx(adreno_dev)) {
hang_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
hang_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
+ hang_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
+ hang_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
+ hang_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
+ hang_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
}
status = kgsl_mmu_start(device);
@@ -1797,6 +1817,7 @@
unsigned int sizebytes)
{
int status = -EINVAL;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
switch (type) {
case KGSL_PROP_PWRCTRL: {
@@ -1816,10 +1837,11 @@
if (enable) {
if (pdata->nap_allowed)
device->pwrctrl.nap_allowed = true;
-
+ adreno_dev->fast_hang_detect = 1;
kgsl_pwrscale_enable(device);
} else {
device->pwrctrl.nap_allowed = false;
+ adreno_dev->fast_hang_detect = 0;
kgsl_pwrscale_disable(device);
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2466a5c..c408f1b 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -2873,12 +2873,22 @@
adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
/*
- * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS
+ * Set SP perfcounter 5 to count SP_ALU_ACTIVE_CYCLES, it includes
+ * all ALU instruction execution regardless precision or shader ID.
+ * Set SP perfcounter 6 to count SP0_ICL1_MISSES, It counts
+ * USP L1 instruction miss request.
+ * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS, it
+ * counts USP flow control instruction execution.
* we will use this to augment our hang detection
*/
-
- adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
- SP_FS_FULL_ALU_INSTRUCTIONS);
+ if (adreno_dev->fast_hang_detect) {
+ adreno_regwrite(device, A3XX_SP_PERFCOUNTER5_SELECT,
+ SP_ALU_ACTIVE_CYCLES);
+ adreno_regwrite(device, A3XX_SP_PERFCOUNTER6_SELECT,
+ SP0_ICL1_MISSES);
+ adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
+ SP_FS_CFLOW_INSTRUCTIONS);
+ }
}
/* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 557ce23..65598ba 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -26,7 +26,7 @@
#define KGSL_TIMEOUT_NONE 0
#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF
-#define KGSL_TIMEOUT_PART 2000 /* 2 sec */
+#define KGSL_TIMEOUT_PART 50 /* 50 msec */
#define FIRST_TIMEOUT (HZ / 2)
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index 2002537..3ea8f4b 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -80,6 +80,10 @@
event->func = cb;
event->owner = owner;
+ /* inc refcount to avoid race conditions in cleanup */
+ if (context)
+ kgsl_context_get(context);
+
/* Add the event to either the owning context or the global list */
if (context) {
@@ -127,6 +131,7 @@
if (event->func)
event->func(device, event->priv, id, cur);
+ kgsl_context_put(context);
list_del(&event->list);
kfree(event);
}
@@ -163,6 +168,9 @@
event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL,
cur);
+ if (event->context)
+ kgsl_context_put(event->context);
+
list_del(&event->list);
kfree(event);
}
@@ -184,6 +192,9 @@
if (event->func)
event->func(device, event->priv, id, timestamp);
+ if (event->context)
+ kgsl_context_put(event->context);
+
list_del(&event->list);
kfree(event);
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 10f8ae1..7016931 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -933,7 +933,8 @@
if (pdata->set_grp_async != NULL)
pdata->set_grp_async();
- if (pdata->num_levels > KGSL_MAX_PWRLEVELS) {
+ if (pdata->num_levels > KGSL_MAX_PWRLEVELS ||
+ pdata->num_levels < 1) {
KGSL_PWR_ERR(device, "invalid power level count: %d\n",
pdata->num_levels);
result = -EINVAL;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 77a0aff..45c67c0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -946,4 +946,15 @@
To compile this driver as a module, choose M here: the
module will be called ft5x06_ts.
+config TOUCHSCREEN_GEN_VKEYS
+ tristate "Touchscreen Virtual Keys Driver"
+ help
+ Say Y here if you want to generate a sysfs entry for virtual
+ keys on Android.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gen_vkeys.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7b28e9d..42b25fe 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -33,6 +33,7 @@
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
+obj-$(CONFIG_TOUCHSCREEN_GEN_VKEYS) += gen_vkeys.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2e807ac..a867fc9 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
- * Copyright (c) 2011-2012, Code Aurora Forum. 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 as published by the
@@ -356,6 +356,7 @@
struct regulator *vcc_ana;
struct regulator *vcc_dig;
struct regulator *vcc_i2c;
+ struct mxt_address_pair addr_pair;
#if defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
@@ -470,9 +471,27 @@
dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
}
-static int mxt_switch_to_bootloader_address(struct mxt_data *data)
+static int mxt_lookup_bootloader_address(struct mxt_data *data)
{
int i;
+
+ for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
+ if (mxt_slave_addresses[i].application ==
+ data->client->addr) {
+ data->addr_pair.bootloader =
+ mxt_slave_addresses[i].bootloader;
+ return 0;
+ }
+ }
+
+ dev_err(&data->client->dev, "Address 0x%02x not found in address table",
+ data->client->addr);
+ return -EINVAL;
+
+};
+
+static int mxt_switch_to_bootloader_address(struct mxt_data *data)
+{
struct i2c_client *client = data->client;
if (data->state == BOOTLOADER) {
@@ -480,27 +499,16 @@
return -EINVAL;
}
- for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
- if (mxt_slave_addresses[i].application == client->addr) {
- dev_info(&client->dev, "Changing to bootloader address: "
- "%02x -> %02x",
- client->addr,
- mxt_slave_addresses[i].bootloader);
+ dev_info(&client->dev, "Changing to bootloader address: 0x%02x -> 0x%02x",
+ client->addr, data->addr_pair.bootloader);
- client->addr = mxt_slave_addresses[i].bootloader;
- data->state = BOOTLOADER;
- return 0;
- }
- }
-
- dev_err(&client->dev, "Address 0x%02x not found in address table",
- client->addr);
- return -EINVAL;
+ client->addr = data->addr_pair.bootloader;
+ data->state = BOOTLOADER;
+ return 0;
}
static int mxt_switch_to_appmode_address(struct mxt_data *data)
{
- int i;
struct i2c_client *client = data->client;
if (data->state == APPMODE) {
@@ -508,23 +516,13 @@
return -EINVAL;
}
- for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
- if (mxt_slave_addresses[i].bootloader == client->addr) {
- dev_info(&client->dev,
- "Changing to application mode address: "
- "0x%02x -> 0x%02x",
- client->addr,
- mxt_slave_addresses[i].application);
+ dev_info(&client->dev, "Changing to application mode address: " \
+ "0x%02x -> 0x%02x", client->addr,
+ data->addr_pair.application);
- client->addr = mxt_slave_addresses[i].application;
- data->state = APPMODE;
- return 0;
- }
- }
-
- dev_err(&client->dev, "Address 0x%02x not found in address table",
- client->addr);
- return -EINVAL;
+ client->addr = data->addr_pair.application;
+ data->state = APPMODE;
+ return 0;
}
static int mxt_get_bootloader_version(struct i2c_client *client, u8 val)
@@ -1655,9 +1653,11 @@
switch (data->info.family_id) {
case MXT224_ID:
case MXT224E_ID:
+ case MXT336S_ID:
max_frame_size = MXT_SINGLE_FW_MAX_FRAME_SIZE;
break;
case MXT1386_ID:
+ case MXT1664S_ID:
max_frame_size = MXT_CHIPSET_FW_MAX_FRAME_SIZE;
break;
default:
@@ -2564,6 +2564,12 @@
return -ENOMEM;
}
+ rc = of_property_read_u32(np, "atmel,bl-addr", &temp_val);
+ if (rc && (rc != -EINVAL))
+ dev_err(dev, "Unable to read bootloader address\n");
+ else if (rc != -EINVAL)
+ pdata->bl_addr = (u8) temp_val;
+
pdata->config_array = info;
for_each_child_of_node(np, temp) {
@@ -2602,7 +2608,7 @@
} else
info->build = (u8) temp_val;
- info->bootldr_id = of_property_read_u32(temp,
+ rc = of_property_read_u32(temp,
"atmel,bootldr-id", &temp_val);
if (rc) {
dev_err(dev, "Unable to read bootldr-id\n");
@@ -2767,6 +2773,13 @@
mxt_power_on_delay(data);
+ data->addr_pair.application = data->client->addr;
+
+ if (pdata->bl_addr)
+ data->addr_pair.bootloader = pdata->bl_addr;
+ else
+ mxt_lookup_bootloader_address(data);
+
error = mxt_initialize(data);
if (error)
goto err_reset_gpio_req;
diff --git a/drivers/input/touchscreen/gen_vkeys.c b/drivers/input/touchscreen/gen_vkeys.c
new file mode 100644
index 0000000..fcda6c9
--- /dev/null
+++ b/drivers/input/touchscreen/gen_vkeys.c
@@ -0,0 +1,219 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/input.h>
+#include <linux/input/gen_vkeys.h>
+
+#define MAX_BUF_SIZE 256
+#define VKEY_VER_CODE "0x01"
+
+#define HEIGHT_SCALE_NUM 8
+#define HEIGHT_SCALE_DENOM 10
+
+/* numerator and denomenator for border equations */
+#define BORDER_ADJUST_NUM 3
+#define BORDER_ADJUST_DENOM 4
+
+static struct kobject *vkey_obj;
+static char *vkey_buf;
+
+static ssize_t vkey_show(struct kobject *obj,
+ struct kobj_attribute *attr, char *buf)
+{
+ strlcpy(buf, vkey_buf, MAX_BUF_SIZE);
+ return strnlen(buf, MAX_BUF_SIZE);
+}
+
+static struct kobj_attribute vkey_obj_attr = {
+ .attr = {
+ .mode = S_IRUGO,
+ },
+ .show = vkey_show,
+};
+
+static struct attribute *vkey_attr[] = {
+ &vkey_obj_attr.attr,
+ NULL,
+};
+
+static struct attribute_group vkey_grp = {
+ .attrs = vkey_attr,
+};
+
+static int __devinit vkey_parse_dt(struct device *dev,
+ struct vkeys_platform_data *pdata)
+{
+ struct device_node *np = dev->of_node;
+ struct property *prop;
+ int rc;
+
+ rc = of_property_read_string(np, "label", &pdata->name);
+ if (rc) {
+ dev_err(dev, "Failed to read label\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(np, "qcom,disp-maxx", &pdata->disp_maxx);
+ if (rc) {
+ dev_err(dev, "Failed to read display max x\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(np, "qcom,disp-maxy", &pdata->disp_maxy);
+ if (rc) {
+ dev_err(dev, "Failed to read display max y\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(np, "qcom,panel-maxx", &pdata->panel_maxx);
+ if (rc) {
+ dev_err(dev, "Failed to read panel max x\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(np, "qcom,panel-maxy", &pdata->panel_maxy);
+ if (rc) {
+ dev_err(dev, "Failed to read panel max y\n");
+ return -EINVAL;
+ }
+
+ prop = of_find_property(np, "qcom,key-codes", NULL);
+ if (prop) {
+ pdata->num_keys = prop->length / sizeof(u32);
+ pdata->keycodes = devm_kzalloc(dev,
+ sizeof(u32) * pdata->num_keys, GFP_KERNEL);
+ if (!pdata->keycodes)
+ return -ENOMEM;
+ rc = of_property_read_u32_array(np, "qcom,key-codes",
+ pdata->keycodes, pdata->num_keys);
+ if (rc) {
+ dev_err(dev, "Failed to read key codes\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int __devinit vkeys_probe(struct platform_device *pdev)
+{
+ struct vkeys_platform_data *pdata;
+ int width, height, center_x, center_y;
+ int x1 = 0, x2 = 0, i, c = 0, ret, border;
+ char *name;
+
+ vkey_buf = devm_kzalloc(&pdev->dev, MAX_BUF_SIZE, GFP_KERNEL);
+ if (!vkey_buf) {
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ if (pdev->dev.of_node) {
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct vkeys_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ ret = vkey_parse_dt(&pdev->dev, pdata);
+ if (ret) {
+ dev_err(&pdev->dev, "Parsing DT failed(%d)", ret);
+ return ret;
+ }
+ } else
+ pdata = pdev->dev.platform_data;
+
+ if (!pdata || !pdata->name || !pdata->keycodes || !pdata->num_keys ||
+ !pdata->disp_maxx || !pdata->disp_maxy || !pdata->panel_maxy) {
+ dev_err(&pdev->dev, "pdata is invalid\n");
+ return -EINVAL;
+ }
+
+ border = (pdata->panel_maxx - pdata->disp_maxx) * 2;
+ width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1)))
+ / pdata->num_keys);
+ height = (pdata->panel_maxy - pdata->disp_maxy);
+ center_y = pdata->disp_maxy + (height / 2);
+ height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM;
+
+ x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM;
+
+ for (i = 0; i < pdata->num_keys; i++) {
+ x1 = x2 + border;
+ x2 = x2 + border + width;
+ center_x = x1 + (x2 - x1) / 2;
+ c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c,
+ "%s:%d:%d:%d:%d:%d\n",
+ VKEY_VER_CODE, pdata->keycodes[i],
+ center_x, center_y, width, height);
+ }
+
+ vkey_buf[c] = '\0';
+
+ name = devm_kzalloc(&pdev->dev, sizeof(*name) * MAX_BUF_SIZE,
+ GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ snprintf(name, MAX_BUF_SIZE,
+ "virtualkeys.%s", pdata->name);
+ vkey_obj_attr.attr.name = name;
+
+ vkey_obj = kobject_create_and_add("board_properties", NULL);
+ if (!vkey_obj) {
+ dev_err(&pdev->dev, "unable to create kobject\n");
+ return -ENOMEM;
+ }
+
+ ret = sysfs_create_group(vkey_obj, &vkey_grp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create attributes\n");
+ goto destroy_kobj;
+ }
+ return 0;
+
+destroy_kobj:
+ kobject_put(vkey_obj);
+
+ return ret;
+}
+
+static int __devexit vkeys_remove(struct platform_device *pdev)
+{
+ sysfs_remove_group(vkey_obj, &vkey_grp);
+ kobject_put(vkey_obj);
+
+ return 0;
+}
+
+static struct of_device_id vkey_match_table[] = {
+ { .compatible = "qcom,gen-vkeys",},
+ { },
+};
+
+static struct platform_driver vkeys_driver = {
+ .probe = vkeys_probe,
+ .remove = __devexit_p(vkeys_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "gen_vkeys",
+ .of_match_table = vkey_match_table,
+ },
+};
+
+module_platform_driver(vkeys_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 490fac8..e57fcd8 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -25,6 +25,7 @@
#include <linux/scatterlist.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/kmemleak.h>
#include <asm/sizes.h>
@@ -120,6 +121,8 @@
goto fail_mem;
}
+ kmemleak_not_leak(buf);
+
return 0;
fail_mem:
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index dc0f7a1..bea6842 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -22,6 +22,7 @@
#include <linux/of_device.h>
#include <linux/spmi.h>
#include <linux/qpnp/pwm.h>
+#include <linux/workqueue.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)
@@ -294,6 +295,7 @@
/**
* struct qpnp_led_data - internal led data structure
* @led_classdev - led class device
+ * @delayed_work - delayed work for turning off the LED
* @id - led index
* @base_reg - base register given in device tree
* @lock - to protect the transactions
@@ -301,10 +303,12 @@
* @num_leds - number of leds in the module
* @max_current - maximum current supported by LED
* @default_on - true: default state max, false, default state 0
+ * @turn_off_delay_ms - number of msec before turning off the LED
*/
struct qpnp_led_data {
struct led_classdev cdev;
struct spmi_device *spmi_dev;
+ struct delayed_work dwork;
int id;
u16 base;
u8 reg;
@@ -315,6 +319,7 @@
struct rgb_config_data *rgb_cfg;
int max_current;
bool default_on;
+ int turn_off_delay_ms;
};
static int
@@ -627,6 +632,23 @@
return led->cdev.brightness;
}
+static void qpnp_led_turn_off_delayed(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct qpnp_led_data *led
+ = container_of(dwork, struct qpnp_led_data, dwork);
+
+ led->cdev.brightness = LED_OFF;
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+}
+
+static void qpnp_led_turn_off(struct qpnp_led_data *led)
+{
+ INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
+ schedule_delayed_work(&led->dwork,
+ msecs_to_jiffies(led->turn_off_delay_ms));
+}
+
static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
{
int rc, i;
@@ -979,6 +1001,7 @@
struct device_node *node)
{
int rc;
+ u32 val;
const char *temp_string;
led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
@@ -998,6 +1021,13 @@
} else if (rc != -EINVAL)
return rc;
+ led->turn_off_delay_ms = 0;
+ rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
+ if (!rc)
+ led->turn_off_delay_ms = val;
+ else if (rc != -EINVAL)
+ return rc;
+
return 0;
}
@@ -1384,9 +1414,11 @@
goto fail_id_check;
}
/* configure default state */
- if (led->default_on)
+ if (led->default_on) {
led->cdev.brightness = led->cdev.max_brightness;
- else
+ 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);
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 042ba37..1c15a41 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -7,7 +7,7 @@
* Copyright (c) 2000 Nokia Research Center
* Tampere, FINLAND
*
- * Copyright (c) 2012, Code Aurora Forum. 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 Lesser General Public License
@@ -100,6 +100,9 @@
int disc_indicator_set;
int pes_length_mismatch;
u64 stc;
+ u32 tei_counter;
+ u32 cont_err_counter;
+ u32 ts_packets_num;
} pes_end;
struct {
@@ -225,8 +228,10 @@
dmx_ts_data_ready_cb callback);
int (*notify_data_read)(struct dmx_ts_feed *feed,
u32 bytes_num);
- int (*set_tsp_out_format) (struct dmx_ts_feed *feed,
+ int (*set_tsp_out_format)(struct dmx_ts_feed *feed,
enum dmx_tsp_format_t tsp_format);
+ int (*set_secure_mode)(struct dmx_ts_feed *feed,
+ struct dmx_secure_mode *sec_mode);
};
/*--------------------------------------------------------------------------*/
@@ -273,6 +278,8 @@
dmx_section_data_ready_cb callback);
int (*notify_data_read)(struct dmx_section_filter *filter,
u32 bytes_num);
+ int (*set_secure_mode)(struct dmx_section_feed *feed,
+ struct dmx_secure_mode *sec_mode);
};
/*--------------------------------------------------------------------------*/
@@ -357,7 +364,6 @@
struct dmx_frontend* frontend; /* Front-end connected to the demux */
void* priv; /* Pointer to private data of the API client */
struct data_buffer dvr_input; /* DVR input buffer */
-
struct dentry *debugfs_demux_dir; /* debugfs dir */
int (*open) (struct dmx_demux* demux);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index f5a505c..c8abe31 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -71,8 +71,8 @@
return;
if (filter->type == DMXDEV_TYPE_SEC) {
- if (filter->feed.sec->notify_data_read)
- filter->feed.sec->notify_data_read(
+ if (filter->feed.sec.feed->notify_data_read)
+ filter->feed.sec.feed->notify_data_read(
filter->filter.sec,
bytes_read);
} else {
@@ -473,16 +473,18 @@
struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
int ret;
size_t todo;
+ int bytes_written;
size_t split;
while (1) {
/* wait for input */
- ret = wait_event_interruptible(src->queue,
- (!src->data) ||
- (dvb_ringbuffer_avail(src)) ||
- (src->error != 0) ||
- (dmxdev->dvr_in_exit) ||
- kthread_should_stop());
+ ret = wait_event_interruptible(
+ src->queue,
+ (!src->data) ||
+ (dvb_ringbuffer_avail(src) > 188) ||
+ (src->error != 0) ||
+ (dmxdev->dvr_in_exit) ||
+ kthread_should_stop());
if ((ret < 0) || kthread_should_stop())
break;
@@ -513,40 +515,60 @@
* In DVR PULL mode, write might block.
* Lock on DVR buffer is released before calling to
* write, if DVR was released meanwhile, dvr_in_exit is
- * prompted. Lock is aquired when updating the read pointer
- * again to preserve read/write pointers consistancy
+ * prompted. Lock is acquired when updating the read pointer
+ * again to preserve read/write pointers consistency
*/
if (split > 0) {
spin_unlock(&dmxdev->dvr_in_lock);
- dmxdev->demux->write(dmxdev->demux,
+ bytes_written = dmxdev->demux->write(dmxdev->demux,
src->data + src->pread,
split);
+ if (bytes_written < 0) {
+ printk(KERN_ERR "dmxdev: dvr write error %d\n",
+ bytes_written);
+ continue;
+ }
+
if (dmxdev->dvr_in_exit)
break;
spin_lock(&dmxdev->dvr_in_lock);
- todo -= split;
- DVB_RINGBUFFER_SKIP(src, split);
+ todo -= bytes_written;
+ DVB_RINGBUFFER_SKIP(src, bytes_written);
+ if (bytes_written < split) {
+ dmxdev->dvr_processing_input = 0;
+ spin_unlock(&dmxdev->dvr_in_lock);
+ wake_up_all(&src->queue);
+ continue;
+ }
+
}
spin_unlock(&dmxdev->dvr_in_lock);
- dmxdev->demux->write(dmxdev->demux,
+ bytes_written = dmxdev->demux->write(dmxdev->demux,
src->data + src->pread, todo);
+ if (bytes_written < 0) {
+ printk(KERN_ERR "dmxdev: dvr write error %d\n",
+ bytes_written);
+ continue;
+ }
+
if (dmxdev->dvr_in_exit)
break;
spin_lock(&dmxdev->dvr_in_lock);
- DVB_RINGBUFFER_SKIP(src, todo);
+ DVB_RINGBUFFER_SKIP(src, bytes_written);
dmxdev->dvr_processing_input = 0;
spin_unlock(&dmxdev->dvr_in_lock);
wake_up_all(&src->queue);
}
+
return 0;
}
@@ -1427,8 +1449,7 @@
struct dmxdev_events_queue *events;
int ret;
- if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
- || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
+ if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
src = &dmxdevfilter->buffer;
events = &dmxdevfilter->events;
} else {
@@ -1762,9 +1783,6 @@
event.params.section.start_offset = dmxdevfilter->buffer.pwrite;
del_timer(&dmxdevfilter->timer);
- dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
- buffer1[0], buffer1[1],
- buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len);
if (ret == buffer1_len)
@@ -1861,6 +1879,9 @@
event.params.pes.flags = 0;
event.params.pes.stc = 0;
+ event.params.pes.transport_error_indicator_counter = 0;
+ event.params.pes.continuity_error_counter = 0;
+ event.params.pes.ts_packets_num = 0;
dvb_dmxdev_add_event(events, &event);
events->current_event_data_size = 0;
@@ -2016,6 +2037,7 @@
}
if (dmx_data_ready->status == DMX_OK_PCR) {
+ dprintk("dmxdev: event callback DMX_OK_PCR\n");
event.type = DMX_EVENT_NEW_PCR;
event.params.pcr.pcr = dmx_data_ready->pcr.pcr;
event.params.pcr.stc = dmx_data_ready->pcr.stc;
@@ -2109,6 +2131,13 @@
DMX_FILTER_PES_LENGTH_ERROR;
event.params.pes.stc = dmx_data_ready->pes_end.stc;
+ event.params.pes.transport_error_indicator_counter =
+ dmx_data_ready->pes_end.tei_counter;
+ event.params.pes.continuity_error_counter =
+ dmx_data_ready->pes_end.cont_err_counter;
+ event.params.pes.ts_packets_num =
+ dmx_data_ready->pes_end.ts_packets_num;
+
dvb_dmxdev_add_event(events, &event);
events->current_event_data_size = 0;
@@ -2153,7 +2182,8 @@
switch (dmxdevfilter->type) {
case DMXDEV_TYPE_SEC:
del_timer(&dmxdevfilter->timer);
- dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
+ dmxdevfilter->feed.sec.feed->stop_filtering(
+ dmxdevfilter->feed.sec.feed);
break;
case DMXDEV_TYPE_PES:
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
@@ -2175,7 +2205,8 @@
switch (filter->type) {
case DMXDEV_TYPE_SEC:
- return filter->feed.sec->start_filtering(filter->feed.sec);
+ return filter->feed.sec.feed->start_filtering(
+ filter->feed.sec.feed);
case DMXDEV_TYPE_PES:
list_for_each_entry(feed, &filter->feed.ts, next) {
ret = feed->ts->start_filtering(feed->ts);
@@ -2209,7 +2240,7 @@
}
filter->dev->demux->release_section_feed(dmxdev->demux,
- filter->feed.sec);
+ filter->feed.sec.feed);
return 0;
}
@@ -2224,15 +2255,15 @@
switch (dmxdevfilter->type) {
case DMXDEV_TYPE_SEC:
- if (!dmxdevfilter->feed.sec)
+ if (!dmxdevfilter->feed.sec.feed)
break;
dvb_dmxdev_feed_stop(dmxdevfilter);
if (dmxdevfilter->filter.sec)
- dmxdevfilter->feed.sec->
- release_filter(dmxdevfilter->feed.sec,
+ dmxdevfilter->feed.sec.feed->
+ release_filter(dmxdevfilter->feed.sec.feed,
dmxdevfilter->filter.sec);
dvb_dmxdev_feed_restart(dmxdevfilter);
- dmxdevfilter->feed.sec = NULL;
+ dmxdevfilter->feed.sec.feed = NULL;
break;
case DMXDEV_TYPE_PES:
dvb_dmxdev_feed_stop(dmxdevfilter);
@@ -2363,6 +2394,9 @@
if (tsfeed->set_tsp_out_format)
tsfeed->set_tsp_out_format(tsfeed, filter->dmx_tsp_format);
+ if (tsfeed->set_secure_mode)
+ tsfeed->set_secure_mode(tsfeed, &feed->sec_mode);
+
/* Support indexing for video PES */
if ((para->pes_type == DMX_PES_VIDEO0) ||
(para->pes_type == DMX_PES_VIDEO1) ||
@@ -2424,7 +2458,7 @@
{
struct dmx_sct_filter_params *para = &filter->params.sec;
struct dmx_section_filter **secfilter = &filter->filter.sec;
- struct dmx_section_feed **secfeed = &filter->feed.sec;
+ struct dmx_section_feed **secfeed = &filter->feed.sec.feed;
*secfilter = NULL;
*secfeed = NULL;
@@ -2434,7 +2468,7 @@
if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
dmxdev->filter[i].params.sec.pid == para->pid) {
- *secfeed = dmxdev->filter[i].feed.sec;
+ *secfeed = dmxdev->filter[i].feed.sec.feed;
break;
}
}
@@ -2471,6 +2505,10 @@
dvb_dmxdev_feed_restart(filter);
return ret;
}
+
+ if ((*secfeed)->set_secure_mode)
+ (*secfeed)->set_secure_mode(*secfeed,
+ &filter->feed.sec.sec_mode);
} else {
dvb_dmxdev_feed_stop(filter);
}
@@ -2478,7 +2516,7 @@
ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
if (ret < 0) {
dvb_dmxdev_feed_restart(filter);
- filter->feed.sec->start_filtering(*secfeed);
+ filter->feed.sec.feed->start_filtering(*secfeed);
dprintk("could not get filter\n");
return ret;
}
@@ -2502,7 +2540,8 @@
filter->todo = 0;
- ret = filter->feed.sec->start_filtering(filter->feed.sec);
+ ret = filter->feed.sec.feed->start_filtering(
+ filter->feed.sec.feed);
if (ret < 0)
return ret;
@@ -2590,6 +2629,7 @@
mutex_lock(&dmxdevfilter->mutex);
dvb_dmxdev_filter_stop(dmxdevfilter);
+
dvb_dmxdev_filter_reset(dmxdevfilter);
if (dmxdevfilter->buffer.data) {
@@ -2643,6 +2683,7 @@
return -ENOMEM;
feed->pid = pid;
+ feed->sec_mode.is_secured = 0;
list_add(&feed->next, &filter->feed.ts);
if (filter->state >= DMXDEV_STATE_GO)
@@ -2685,6 +2726,7 @@
memcpy(&dmxdevfilter->params.sec,
params, sizeof(struct dmx_sct_filter_params));
invert_mode(&dmxdevfilter->params.sec.filter);
+ dmxdevfilter->feed.sec.sec_mode.is_secured = 0;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
if (params->flags & DMX_IMMEDIATE_START)
@@ -2693,6 +2735,64 @@
return 0;
}
+static int dvb_dmxdev_set_secure_mode(
+ struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter,
+ struct dmx_secure_mode *sec_mode)
+{
+ struct dmxdev_feed *feed;
+ struct dmxdev_feed *ts_feed = NULL;
+ struct dmxdev_sec_feed *sec_feed = NULL;
+
+ if (NULL == dmxdev || NULL == filter || NULL == sec_mode)
+ return -EINVAL;
+
+ if (filter->state < DMXDEV_STATE_SET ||
+ filter->state > DMXDEV_STATE_GO) {
+ printk(KERN_ERR "%s: invalid filter state\n", __func__);
+ return -EPERM;
+ }
+ dprintk(KERN_DEBUG "%s: key_id=%d, secure=%d, looking for pid=%d\n",
+ __func__, sec_mode->key_ladder_id, sec_mode->is_secured,
+ sec_mode->pid);
+ switch (filter->type) {
+ case DMXDEV_TYPE_PES:
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ if (feed->pid == sec_mode->pid) {
+ ts_feed = feed;
+ ts_feed->sec_mode = *sec_mode;
+ if (filter->state == DMXDEV_STATE_GO &&
+ ts_feed->ts->set_secure_mode)
+ ts_feed->ts->set_secure_mode(
+ ts_feed->ts, sec_mode);
+ break;
+ }
+ }
+ break;
+ case DMXDEV_TYPE_SEC:
+ if (filter->params.sec.pid == sec_mode->pid) {
+ sec_feed = &filter->feed.sec;
+ sec_feed->sec_mode = *sec_mode;
+ if (filter->state == DMXDEV_STATE_GO &&
+ sec_feed->feed->set_secure_mode)
+ sec_feed->feed->set_secure_mode(sec_feed->feed,
+ sec_mode);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (!ts_feed && !sec_feed) {
+ printk(KERN_ERR "%s: pid %d is undefined for this filter\n",
+ __func__, sec_mode->pid);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_pes_filter_params *params)
@@ -2754,8 +2854,10 @@
dec_buffs = &filter->decoder_buffers;
dmxdev->demux->get_caps(dmxdev->demux, &caps);
- if (0 == buffs->buffers_size ||
- (buffs->is_linear && buffs->buffers_num <= 1))
+ if ((buffs->buffers_size == 0) ||
+ (buffs->is_linear &&
+ ((buffs->buffers_num <= 1) ||
+ (buffs->buffers_num > DMX_MAX_DECODER_BUFFER_NUM))))
return -EINVAL;
if (0 == buffs->buffers_num) {
@@ -3081,6 +3183,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_SECURE_MODE:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_set_secure_mode(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
case DMX_REUSE_DECODER_BUFFER:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
@@ -3191,9 +3302,7 @@
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
-
int ret;
-
ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
mutex_lock(&dmxdev->mutex);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 0f7da1b..3ab4bad 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -58,10 +58,16 @@
struct dmxdev_feed {
u16 pid;
+ struct dmx_secure_mode sec_mode;
struct dmx_ts_feed *ts;
struct list_head next;
};
+struct dmxdev_sec_feed {
+ struct dmx_secure_mode sec_mode;
+ struct dmx_section_feed *feed;
+};
+
struct dmxdev_events_queue {
#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
/*
@@ -99,7 +105,7 @@
union {
/* list of TS and PES feeds (struct dmxdev_feed) */
struct list_head ts;
- struct dmx_section_feed *sec;
+ struct dmxdev_sec_feed sec;
} feed;
union {
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index eea83c2..dfb8d58 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,7 +5,7 @@
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
- * Copyright (c) 2012, Code Aurora Forum. 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 Lesser General Public License
@@ -127,15 +127,15 @@
{
int count = payload(buf);
int p;
- //int ccok;
- //u8 cc;
+ int ccok;
+ u8 cc;
+ struct dmx_data_ready data;
if (count == 0)
return -1;
p = 188 - count;
- /*
cc = buf[3] & 0x0f;
if (feed->first_cc)
ccok = 1;
@@ -144,26 +144,41 @@
feed->first_cc = 0;
feed->cc = cc;
- if (!ccok)
- printk("missed packet!\n");
- */
/* PUSI ? */
if (buf[1] & 0x40) {
- if (feed->pusi_seen)
+ if (feed->pusi_seen) {
/* We had seen PUSI before, this means
* that previous PES can be closed now.
*/
- feed->cb.ts(NULL, 0, NULL, 0,
- &feed->feed.ts, DMX_OK_PES_END);
+ data.status = DMX_OK_PES_END;
+ data.data_length = 0;
+ data.pes_end.start_gap = 0;
+ data.pes_end.actual_length = feed->peslen;
+ data.pes_end.disc_indicator_set = 0;
+ data.pes_end.pes_length_mismatch = 0;
+ data.pes_end.stc = 0;
+ data.pes_end.tei_counter = feed->pes_tei_counter;
+ data.pes_end.cont_err_counter =
+ feed->pes_cont_err_counter;
+ data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ }
feed->pusi_seen = 1;
feed->peslen = 0;
+ feed->pes_tei_counter = 0;
+ feed->pes_ts_packets_num = 0;
+ feed->pes_cont_err_counter = 0;
}
if (feed->pusi_seen == 0)
return 0;
+ feed->pes_ts_packets_num++;
+ feed->pes_cont_err_counter += !ccok;
+ feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0;
+
feed->peslen += count;
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
@@ -1192,6 +1207,24 @@
return 0;
}
+static int dmx_ts_set_secure_mode(struct dmx_ts_feed *feed,
+ struct dmx_secure_mode *secure_mode)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ dvbdmxfeed->secure_mode = *secure_mode;
+
+ if ((dvbdmxfeed->state == DMX_STATE_GO) &&
+ dvbdmxfeed->demux->set_secure_mode)
+ dvbdmxfeed->demux->set_secure_mode(dvbdmxfeed, secure_mode);
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
static int dmx_ts_set_indexing_params(
struct dmx_ts_feed *ts_feed,
struct dmx_indexing_video_params *params)
@@ -1243,6 +1276,10 @@
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0;
+ feed->pes_tei_counter = 0;
+ feed->pes_ts_packets_num = 0;
+ feed->pes_cont_err_counter = 0;
+ feed->secure_mode.is_secured = 0;
feed->buffer = NULL;
feed->tsp_out_format = DMX_TSP_FORMAT_188;
memset(&feed->indexing_params, 0,
@@ -1268,6 +1305,7 @@
(*ts_feed)->reuse_decoder_buffer = dmx_ts_feed_reuse_decoder_buffer;
(*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
(*ts_feed)->notify_data_read = NULL;
+ (*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
@@ -1496,6 +1534,23 @@
return 0;
}
+static int dmx_section_set_secure_mode(struct dmx_section_feed *feed,
+ struct dmx_secure_mode *secure_mode)
+{
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ dvbdmxfeed->secure_mode = *secure_mode;
+ if ((dvbdmxfeed->state == DMX_STATE_GO) &&
+ dvbdmxfeed->demux->set_secure_mode)
+ dvbdmxfeed->demux->set_secure_mode(dvbdmxfeed, secure_mode);
+
+ mutex_unlock(&dvbdmx->mutex);
+ return 0;
+}
+
static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
struct dmx_section_filter *filter)
{
@@ -1549,6 +1604,7 @@
dvbdmxfeed->cb.sec = callback;
dvbdmxfeed->demux = dvbdmx;
dvbdmxfeed->pid = 0xffff;
+ dvbdmxfeed->secure_mode.is_secured = 0;
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->feed.sec.tsfeedp = 0;
@@ -1567,6 +1623,7 @@
(*feed)->release_filter = dmx_section_feed_release_filter;
(*feed)->data_ready_cb = dmx_section_feed_data_ready_cb;
(*feed)->notify_data_read = NULL;
+ (*feed)->set_secure_mode = dmx_section_set_secure_mode;
mutex_unlock(&dvbdmx->mutex);
return 0;
@@ -1757,6 +1814,19 @@
mutex_lock(&dvbdemux->mutex);
dvbdemux->tsp_format = tsp_format;
+ switch (tsp_format) {
+ case DMX_TSP_FORMAT_188:
+ dvbdemux->ts_packet_size = 188;
+ break;
+ case DMX_TSP_FORMAT_192_TAIL:
+ case DMX_TSP_FORMAT_192_HEAD:
+ dvbdemux->ts_packet_size = 192;
+ break;
+ case DMX_TSP_FORMAT_204:
+ dvbdemux->ts_packet_size = 204;
+ break;
+ }
+
mutex_unlock(&dvbdemux->mutex);
return 0;
}
@@ -1831,6 +1901,7 @@
dvbdemux->tsbufp = 0;
dvbdemux->tsp_format = DMX_TSP_FORMAT_188;
+ dvbdemux->ts_packet_size = 188;
if (!dvbdemux->check_crc32)
dvbdemux->check_crc32 = dvb_dmx_crc32;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 2e4a468..f5f6039 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -4,7 +4,7 @@
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
* for convergence integrated media GmbH
*
- * Copyright (c) 2012, Code Aurora Forum. 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 Lesser General Public License
@@ -93,6 +93,7 @@
u8 *buffer;
int buffer_size;
enum dmx_tsp_format_t tsp_out_format;
+ struct dmx_secure_mode secure_mode;
struct timespec timeout;
struct dvb_demux_filter *filter;
@@ -105,6 +106,9 @@
int pusi_seen; /* prevents feeding of garbage from previous section */
u32 peslen;
+ u32 pes_tei_counter;
+ u32 pes_cont_err_counter;
+ u32 pes_ts_packets_num;
struct list_head list_head;
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
@@ -129,6 +133,8 @@
struct dmx_buffer_status *dmx_buffer_status);
int (*reuse_decoder_buffer)(struct dvb_demux_feed *feed,
int cookie);
+ int (*set_secure_mode)(struct dvb_demux_feed *feed,
+ struct dmx_secure_mode *secure_mode);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
@@ -160,6 +166,7 @@
uint32_t speed_pkts_cnt; /* for TS speed check */
enum dmx_tsp_format_t tsp_format;
+ size_t ts_packet_size;
enum dmx_playback_mode_t playback_mode;
int sw_filter_abort;
diff --git a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
index 6840858..6ec1994 100644
--- a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -177,13 +177,6 @@
if ((NULL == sbuff) || (NULL == packet))
return -EINVAL;
- MPQ_DVB_DBG_PRINT(
- "%s: handle=%d, offset=%d, len=%d\n",
- __func__,
- packet->raw_data_handle,
- packet->raw_data_offset,
- packet->raw_data_len);
-
len = sizeof(struct mpq_streambuffer_packet_header) +
packet->user_data_len;
@@ -270,9 +263,6 @@
}
memcpy(desc->base + desc->write_ptr, buf, len);
desc->write_ptr += len;
- MPQ_DVB_DBG_PRINT(
- "%s: copied %d data bytes. handle=%d, write_ptr=%d\n",
- __func__, len, desc->handle, desc->write_ptr);
res = len;
}
@@ -288,10 +278,10 @@
if (NULL == sbuff)
return -EINVAL;
- if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
- return -ENOSPC;
-
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+ return -ENOSPC;
+
DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len);
wake_up_all(&sbuff->raw_data.queue);
} else {
diff --git a/drivers/media/dvb/mpq/demux/Makefile b/drivers/media/dvb/mpq/demux/Makefile
index b9310c3..9f4a03e 100644
--- a/drivers/media/dvb/mpq/demux/Makefile
+++ b/drivers/media/dvb/mpq/demux/Makefile
@@ -1,14 +1,18 @@
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-EXTRA_CFLAGS += -Idrivers/media/dvb/mpq/include/
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/mpq/include/
+ccflags-y += -Idrivers/misc/
obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o
mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o
+mpq-dmx-hw-plugin-y += mpq_sdmx.o
+
mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o
mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP2) += mpq_dmx_plugin_tspp_v2.o
mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSIF) += mpq_dmx_plugin_tsif.o
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 4b67477..615342c 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.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
@@ -16,11 +16,34 @@
#include <linux/file.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
+#include "mpq_sdmx.h"
+#define TS_PACKET_HEADER_LENGTH (4)
/* Length of mandatory fields that must exist in header of video PES */
#define PES_MANDATORY_FIELDS_LEN 9
+#define MAX_PES_LENGTH (SZ_64K)
+
+/*
+ * PES header length field is 8 bits so PES header length after this field
+ * can be up to 256 bytes.
+ * Preceding fields of the PES header total to 9 bytes
+ * (including the PES header length field).
+ */
+#define MAX_PES_HEADER_LENGTH (256 + PES_MANDATORY_FIELDS_LEN)
+
+/* TS packet with adaptation field only can take up the entire TSP */
+#define MAX_TSP_ADAPTATION_LENGTH (184)
+
+#define MAX_SDMX_METADATA_LENGTH \
+ (TS_PACKET_HEADER_LENGTH + \
+ MAX_TSP_ADAPTATION_LENGTH + \
+ MAX_PES_HEADER_LENGTH)
+
+#define SDMX_METADATA_BUFFER_SIZE (64*1024)
+#define SDMX_SECTION_BUFFER_SIZE (64*1024)
+#define SDMX_PCR_BUFFER_SIZE (64*1024)
/*
* 500 PES header packets in the meta-data buffer,
@@ -52,6 +75,18 @@
module_param(generate_es_events, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(generate_es_events, "Generate new elementary stream data events");
+/* Value of TS packet scramble bits field for even key */
+static int mpq_sdmx_scramble_even = 0x2;
+module_param(mpq_sdmx_scramble_even, int, S_IRUGO | S_IWUSR);
+
+/* Value of TS packet scramble bits field for odd key */
+static int mpq_sdmx_scramble_odd = 0x3;
+module_param(mpq_sdmx_scramble_odd, int, S_IRUGO | S_IWUSR);
+
+/* Whether to use secure demux or bypass it. Use for debugging */
+static int mpq_bypass_sdmx = 1;
+module_param(mpq_bypass_sdmx, int, S_IRUGO | S_IWUSR);
+
/**
* Maximum allowed framing pattern size
*/
@@ -144,6 +179,9 @@
* in the meta-data passed to the decoder.
*/
int decoder_framing;
+
+ /* Indicates whether secure demux TZ application is available */
+ int secure_demux_app_loaded;
} mpq_dmx_info;
/* Check that PES header is valid and that it is a video PES */
@@ -477,6 +515,104 @@
return 0;
}
+/*
+ * mpq_dmx_calc_time_delta -
+ * Calculate delta in msec between two time snapshots.
+ *
+ * @curr_time: value of current time
+ * @prev_time: value of previous time
+ *
+ * Return time-delta in msec
+ */
+static inline u32 mpq_dmx_calc_time_delta(struct timespec *curr_time,
+ struct timespec *prev_time)
+{
+ struct timespec delta_time;
+ u64 delta_time_ms;
+
+ delta_time = timespec_sub(*curr_time, *prev_time);
+
+ delta_time_ms = ((u64)delta_time.tv_sec * MSEC_PER_SEC) +
+ delta_time.tv_nsec / NSEC_PER_MSEC;
+
+ return (u32)delta_time_ms;
+}
+
+/*
+ * mpq_dmx_update_decoder_stat -
+ * Update decoder output statistics in debug-fs.
+ *
+ * @mpq_demux: mpq_demux object
+ */
+static inline void mpq_dmx_update_decoder_stat(struct mpq_demux *mpq_demux)
+{
+ struct timespec curr_time;
+ u64 delta_time_ms;
+
+ curr_time = current_kernel_time();
+ if (unlikely(!mpq_demux->decoder_out_count)) {
+ mpq_demux->decoder_out_last_time = curr_time;
+ mpq_demux->decoder_out_count++;
+ return;
+ }
+
+ /* calculate time-delta between frame */
+ delta_time_ms = mpq_dmx_calc_time_delta(&curr_time,
+ &mpq_demux->decoder_out_last_time);
+
+ mpq_demux->decoder_out_interval_sum += (u32)delta_time_ms;
+
+ mpq_demux->decoder_out_interval_average =
+ mpq_demux->decoder_out_interval_sum /
+ mpq_demux->decoder_out_count;
+
+ if (delta_time_ms > mpq_demux->decoder_out_interval_max)
+ mpq_demux->decoder_out_interval_max = delta_time_ms;
+
+ mpq_demux->decoder_out_last_time = curr_time;
+ mpq_demux->decoder_out_count++;
+}
+
+/*
+ * mpq_dmx_update_sdmx_stat -
+ * Update SDMX statistics in debug-fs.
+ *
+ * @mpq_demux: mpq_demux object
+ * @bytes_processed: number of bytes processed by sdmx
+ * @process_start_time: time before sdmx process was triggered
+ * @process_end_time: time after sdmx process finished
+ */
+static inline void mpq_dmx_update_sdmx_stat(struct mpq_demux *mpq_demux,
+ u32 bytes_processed, struct timespec *process_start_time,
+ struct timespec *process_end_time)
+{
+ u32 packets_num;
+ u64 process_time;
+
+ mpq_demux->sdmx_process_count++;
+ packets_num = bytes_processed / mpq_demux->demux.ts_packet_size;
+ mpq_demux->sdmx_process_packets_sum += packets_num;
+ mpq_demux->sdmx_process_packets_average =
+ mpq_demux->sdmx_process_packets_sum /
+ mpq_demux->sdmx_process_count;
+
+ process_time =
+ mpq_dmx_calc_time_delta(process_end_time, process_start_time);
+
+ mpq_demux->sdmx_process_time_sum += process_time;
+ mpq_demux->sdmx_process_time_average =
+ mpq_demux->sdmx_process_time_sum /
+ mpq_demux->sdmx_process_count;
+
+ if ((mpq_demux->sdmx_process_count == 1) ||
+ (packets_num < mpq_demux->sdmx_process_packets_min))
+ mpq_demux->sdmx_process_packets_min = packets_num;
+
+ if ((mpq_demux->sdmx_process_count == 1) ||
+ (process_time > mpq_demux->sdmx_process_time_max))
+ mpq_demux->sdmx_process_time_max = process_time;
+}
+
/* Extend dvb-demux debugfs with HW statistics */
void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux)
{
@@ -490,93 +626,130 @@
mpq_demux->hw_notification_size = 0;
mpq_demux->hw_notification_min_size = 0xFFFFFFFF;
- if (mpq_demux->demux.dmx.debugfs_demux_dir != NULL) {
- debugfs_create_u32(
- "hw_notification_interval",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_interval);
+ if (mpq_demux->demux.dmx.debugfs_demux_dir == NULL)
+ return;
- debugfs_create_u32(
- "hw_notification_min_interval",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_min_interval);
+ debugfs_create_u32(
+ "hw_notification_interval",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_interval);
- debugfs_create_u32(
- "hw_notification_count",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_count);
+ debugfs_create_u32(
+ "hw_notification_min_interval",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_min_interval);
- debugfs_create_u32(
- "hw_notification_size",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_size);
+ debugfs_create_u32(
+ "hw_notification_count",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_count);
- debugfs_create_u32(
- "hw_notification_min_size",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_min_size);
+ debugfs_create_u32(
+ "hw_notification_size",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_size);
- debugfs_create_u32(
- "decoder_drop_count",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->decoder_drop_count);
+ debugfs_create_u32(
+ "hw_notification_min_size",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_min_size);
- debugfs_create_u32(
- "decoder_out_count",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->decoder_out_count);
+ debugfs_create_u32(
+ "decoder_drop_count",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_drop_count);
- debugfs_create_u32(
- "decoder_out_interval_sum",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->decoder_out_interval_sum);
+ debugfs_create_u32(
+ "decoder_out_count",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_out_count);
- debugfs_create_u32(
- "decoder_out_interval_average",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->decoder_out_interval_average);
+ debugfs_create_u32(
+ "decoder_out_interval_sum",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_out_interval_sum);
- debugfs_create_u32(
- "decoder_out_interval_max",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->decoder_out_interval_max);
+ debugfs_create_u32(
+ "decoder_out_interval_average",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_out_interval_average);
- debugfs_create_u32(
- "decoder_ts_errors",
- S_IRUGO|S_IWUGO,
- mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->decoder_ts_errors);
- }
+ debugfs_create_u32(
+ "decoder_out_interval_max",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_out_interval_max);
+
+ debugfs_create_u32(
+ "decoder_ts_errors",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->decoder_ts_errors);
+
+ debugfs_create_u32(
+ "sdmx_process_count",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_count);
+
+ debugfs_create_u32(
+ "sdmx_process_time_sum",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_time_sum);
+
+ debugfs_create_u32(
+ "sdmx_process_time_average",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_time_average);
+
+ debugfs_create_u32(
+ "sdmx_process_time_max",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_time_max);
+
+ debugfs_create_u32(
+ "sdmx_process_packets_sum",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_packets_sum);
+
+ debugfs_create_u32(
+ "sdmx_process_packets_average",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_packets_average);
+
+ debugfs_create_u32(
+ "sdmx_process_packets_min",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->sdmx_process_packets_min);
}
EXPORT_SYMBOL(mpq_dmx_init_hw_statistics);
-
/* Update dvb-demux debugfs with HW notification statistics */
void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux)
{
- struct timespec curr_time, delta_time;
+ struct timespec curr_time;
u64 delta_time_ms;
curr_time = current_kernel_time();
if (likely(mpq_demux->hw_notification_count)) {
/* calculate time-delta between notifications */
- delta_time =
- timespec_sub(
- curr_time,
- mpq_demux->last_notification_time);
-
- delta_time_ms = ((u64)delta_time.tv_sec * MSEC_PER_SEC) +
- delta_time.tv_nsec / NSEC_PER_MSEC;
+ delta_time_ms = mpq_dmx_calc_time_delta(&curr_time,
+ &mpq_demux->last_notification_time);
mpq_demux->hw_notification_interval = delta_time_ms;
@@ -593,13 +766,32 @@
}
EXPORT_SYMBOL(mpq_dmx_update_hw_statistics);
+static void mpq_sdmx_check_app_loaded(void)
+{
+ int session;
+ int ret;
+
+ ret = sdmx_open_session(&session);
+ if (ret != SDMX_SUCCESS) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Could not initialize session with SDMX. ret = %d\n",
+ __func__, ret);
+ mpq_dmx_info.secure_demux_app_loaded = 0;
+ return;
+ }
+
+ mpq_dmx_info.secure_demux_app_loaded = 1;
+ sdmx_close_session(session);
+}
int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func)
{
int i;
+ int j;
int result;
struct mpq_demux *mpq_demux;
struct dvb_adapter *mpq_adapter;
+ struct mpq_feed *feed;
MPQ_DVB_DBG_PRINT("%s executed, device num %d\n",
__func__,
@@ -627,6 +819,8 @@
mpq_dmx_info.devices = NULL;
mpq_dmx_info.ion_client = NULL;
+ mpq_sdmx_check_app_loaded();
+
/*
* TODO: the following should be set based on the decoder:
* 0 means the decoder doesn't handle framing, so framing
@@ -636,7 +830,7 @@
/* Allocate memory for all MPQ devices */
mpq_dmx_info.devices =
- vmalloc(mpq_demux_device_num*sizeof(struct mpq_demux));
+ vzalloc(mpq_demux_device_num*sizeof(struct mpq_demux));
if (!mpq_dmx_info.devices) {
MPQ_DVB_ERR_PRINT(
@@ -647,11 +841,6 @@
goto init_failed;
}
- /* Zero allocated memory */
- memset(mpq_dmx_info.devices,
- 0,
- mpq_demux_device_num*sizeof(struct mpq_demux));
-
/*
* Create a new ION client used by demux to allocate memory
* for decoder's buffers.
@@ -684,7 +873,27 @@
*/
mpq_demux->ion_client = mpq_dmx_info.ion_client;
- spin_lock_init(&mpq_demux->feed_lock);
+ mutex_init(&mpq_demux->mutex);
+
+ mpq_demux->sdmx_filter_count = 0;
+ mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+
+ if (mpq_demux->demux.feednum > MPQ_MAX_DMX_FILES) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: err - actual feednum (%d) larger than max, enlarge MPQ_MAX_DMX_FILES!\n",
+ __func__,
+ mpq_demux->demux.feednum);
+ result = -EINVAL;
+ goto init_failed_free_demux_devices;
+ }
+
+ /* Initialize private feed info */
+ for (j = 0; j < MPQ_MAX_DMX_FILES; j++) {
+ feed = &mpq_demux->feeds[j];
+ memset(feed, 0, sizeof(*feed));
+ feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE;
+ feed->mpq_demux = mpq_demux;
+ }
/*
* mpq_demux_plugin_hw_init should be implemented
@@ -703,6 +912,16 @@
mpq_demux->is_initialized = 1;
/*
+ * dvb-demux is now initialized,
+ * update back-pointers of private feeds
+ */
+ for (j = 0; j < MPQ_MAX_DMX_FILES; j++) {
+ feed = &mpq_demux->feeds[j];
+ feed->dvb_demux_feed = &mpq_demux->demux.feed[j];
+ mpq_demux->demux.feed[j].priv = feed;
+ }
+
+ /*
* Add capability of receiving input from memory.
* Every demux in our system may be connected to memory input,
* or any live input.
@@ -732,7 +951,6 @@
}
EXPORT_SYMBOL(mpq_dmx_plugin_init);
-
void mpq_dmx_plugin_exit(void)
{
int i;
@@ -754,6 +972,9 @@
&mpq_demux->demux.dmx,
&mpq_demux->fe_memory);
+ if (mpq_sdmx_is_loaded())
+ mpq_sdmx_close_session(mpq_demux);
+ mutex_destroy(&mpq_demux->mutex);
dvb_dmxdev_release(&mpq_demux->dmxdev);
dvb_dmx_release(&mpq_demux->demux);
}
@@ -853,7 +1074,7 @@
unsigned long ionflag = 0;
int ret;
- if (NULL == client || priv_handle == NULL || kernel_mem == NULL) {
+ if (client == NULL || priv_handle == NULL || kernel_mem == NULL) {
MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
return -EINVAL;
}
@@ -880,6 +1101,7 @@
MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
*kernel_mem = NULL;
} else {
+ unsigned long tmp;
*kernel_mem = ion_map_kernel(client, ion_handle);
if (*kernel_mem == NULL) {
MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
@@ -887,6 +1109,10 @@
ret = -ENOMEM;
goto map_buffer_failed_free_buff;
}
+ ion_handle_get_size(client, ion_handle, &tmp);
+ MPQ_DVB_DBG_PRINT(
+ "%s: mapped to address 0x%p, size=%lu\n",
+ __func__, *kernel_mem, tmp);
}
*priv_handle = ion_handle;
@@ -978,32 +1204,28 @@
if (mpq_dmx_is_video_feed(feed)) {
struct mpq_video_feed_info *feed_data;
+ struct mpq_feed *mpq_feed;
struct mpq_streambuffer *stream_buffer;
int ret;
- spin_lock(&mpq_demux->feed_lock);
+ mutex_lock(&mpq_demux->mutex);
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
- if (feed->priv == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: invalid feed, feed->priv is NULL\n",
- __func__);
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- feed_data = feed->priv;
+ spin_lock(&feed_data->video_buffer_lock);
stream_buffer = feed_data->video_buffer;
if (stream_buffer == NULL) {
MPQ_DVB_ERR_PRINT(
"%s: invalid feed, feed_data->video_buffer is NULL\n",
__func__);
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
+ mutex_unlock(&mpq_demux->mutex);
return -EINVAL;
}
ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1);
-
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
+ mutex_unlock(&mpq_demux->mutex);
return ret;
}
@@ -1193,18 +1415,18 @@
* Return error status
*/
static int mpq_dmx_init_streambuffer(
- struct dvb_demux_feed *feed,
+ struct mpq_feed *feed,
struct mpq_video_feed_info *feed_data,
struct mpq_streambuffer *stream_buffer)
{
int ret;
void *packet_buffer = NULL;
- struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_demux *mpq_demux = feed->mpq_demux;
struct ion_client *client = mpq_demux->ion_client;
struct dmx_decoder_buffers *dec_buffs = NULL;
enum mpq_streambuffer_mode mode;
- dec_buffs = feed->feed.ts.decoder_buffers;
+ dec_buffs = feed->dvb_demux_feed->feed.ts.decoder_buffers;
/* Allocate packet buffer holding the meta-data */
packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
@@ -1258,17 +1480,19 @@
}
static void mpq_dmx_release_streambuffer(
- struct dvb_demux_feed *feed,
+ struct mpq_feed *feed,
struct mpq_video_feed_info *feed_data,
+ struct mpq_streambuffer *video_buffer,
struct ion_client *client)
{
int buf_num = 0;
int i;
- struct dmx_decoder_buffers *dec_buffs = feed->feed.ts.decoder_buffers;
+ struct dmx_decoder_buffers *dec_buffs =
+ feed->dvb_demux_feed->feed.ts.decoder_buffers;
mpq_adapter_unregister_stream_if(feed_data->stream_interface);
- vfree(feed_data->video_buffer->packet_data.data);
+ vfree(video_buffer->packet_data.data);
buf_num = feed_data->buffer_desc.decoder_buffers_num;
@@ -1303,29 +1527,26 @@
}
}
-int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed)
+/**
+ * mpq_dmx_init_video_feed - Initializes of video feed information
+ * used to pass data directly to decoder.
+ *
+ * @mpq_feed: The mpq feed object
+ *
+ * Return error code.
+ */
+static int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed)
{
int ret;
- struct mpq_video_feed_info *feed_data;
- struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_video_feed_info *feed_data = &mpq_feed->video_info;
+ struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
struct mpq_streambuffer *stream_buffer;
- /* Allocate memory for private feed data */
- feed_data = vzalloc(sizeof(struct mpq_video_feed_info));
-
- if (feed_data == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: FAILED to allocate private video feed data\n",
- __func__);
-
- ret = -ENOMEM;
- goto init_failed;
- }
-
/* get and store framing information if required */
if (!mpq_dmx_info.decoder_framing) {
- mpq_dmx_get_pattern_params(&feed->indexing_params,
- &feed_data->patterns, &feed_data->patterns_num);
+ mpq_dmx_get_pattern_params(
+ &mpq_feed->dvb_demux_feed->indexing_params,
+ &feed_data->patterns, &feed_data->patterns_num);
if (feed_data->patterns == NULL) {
MPQ_DVB_ERR_PRINT(
"%s: FAILED to get framing pattern parameters\n",
@@ -1337,7 +1558,7 @@
}
/* Register the new stream-buffer interface to MPQ adapter */
- switch (feed->pes_type) {
+ switch (mpq_feed->dvb_demux_feed->pes_type) {
case DMX_TS_PES_VIDEO0:
feed_data->stream_interface =
MPQ_ADAPTER_VIDEO0_STREAM_IF;
@@ -1362,7 +1583,7 @@
MPQ_DVB_ERR_PRINT(
"%s: Invalid pes type %d\n",
__func__,
- feed->pes_type);
+ mpq_feed->dvb_demux_feed->pes_type);
ret = -EINVAL;
goto init_failed_free_priv_data;
}
@@ -1385,7 +1606,7 @@
&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
ret = mpq_dmx_init_streambuffer(
- feed, feed_data, feed_data->video_buffer);
+ mpq_feed, feed_data, feed_data->video_buffer);
if (ret) {
MPQ_DVB_ERR_PRINT(
"%s: mpq_dmx_init_streambuffer failed, err = %d\n",
@@ -1405,13 +1626,12 @@
goto init_failed_free_stream_buffer;
}
- feed_data->pes_payload_address =
- (u32)feed_data->video_buffer->raw_data.data;
+ spin_lock_init(&feed_data->video_buffer_lock);
feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
feed_data->pes_header_offset = 0;
- feed->pusi_seen = 0;
- feed->peslen = 0;
+ mpq_feed->dvb_demux_feed->pusi_seen = 0;
+ mpq_feed->dvb_demux_feed->peslen = 0;
feed_data->fullness_wait_cancel = 0;
mpq_streambuffer_get_data_rw_offset(feed_data->video_buffer, NULL,
&feed_data->frame_offset);
@@ -1442,76 +1662,306 @@
mpq_demux->decoder_out_interval_max = 0;
mpq_demux->decoder_ts_errors = 0;
- spin_lock(&mpq_demux->feed_lock);
- feed->priv = (void *)feed_data;
- spin_unlock(&mpq_demux->feed_lock);
-
return 0;
init_failed_free_stream_buffer:
- mpq_dmx_release_streambuffer(feed, feed_data, mpq_demux->ion_client);
+ mpq_dmx_release_streambuffer(mpq_feed, feed_data,
+ feed_data->video_buffer, mpq_demux->ion_client);
mpq_adapter_unregister_stream_if(feed_data->stream_interface);
init_failed_free_priv_data:
- vfree(feed_data);
- feed->priv = NULL;
-init_failed:
-
+ feed_data->video_buffer = NULL;
return ret;
}
-EXPORT_SYMBOL(mpq_dmx_init_video_feed);
-int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed)
+/**
+ * mpq_dmx_terminate_video_feed - terminate video feed information
+ * that was previously initialized in mpq_dmx_init_video_feed
+ *
+ * @mpq_feed: The mpq feed used for the video TS packets
+ *
+ * Return error code.
+ */
+static int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed)
{
+ struct mpq_streambuffer *video_buffer;
struct mpq_video_feed_info *feed_data;
- struct mpq_demux *mpq_demux;
+ struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
- if (feed->priv == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: invalid feed, feed->priv is NULL\n",
- __func__);
-
+ if (mpq_feed == NULL)
return -EINVAL;
- }
- mpq_demux = feed->demux->priv;
- feed_data = feed->priv;
+ feed_data = &mpq_feed->video_info;
- spin_lock(&mpq_demux->feed_lock);
- feed->priv = NULL;
- spin_unlock(&mpq_demux->feed_lock);
+ spin_lock(&feed_data->video_buffer_lock);
+ video_buffer = feed_data->video_buffer;
+ feed_data->video_buffer = NULL;
+ wake_up_all(&video_buffer->raw_data.queue);
+ spin_unlock(&feed_data->video_buffer_lock);
- wake_up_all(&feed_data->video_buffer->raw_data.queue);
-
- mpq_dmx_release_streambuffer(feed, feed_data, mpq_demux->ion_client);
-
- vfree(feed_data);
+ mpq_dmx_release_streambuffer(mpq_feed, feed_data,
+ video_buffer, mpq_demux->ion_client);
return 0;
}
-EXPORT_SYMBOL(mpq_dmx_terminate_video_feed);
+
+/**
+ * mpq_sdmx_lookup_feed() - Search for a feed object that shares the same
+ * filter of the specified feed object, and return it
+ *
+ * @feed: dvb demux feed object
+ *
+ * Return the mpq_feed sharing the same filter's buffer or NULL if no
+ * such is found.
+ */
+static struct mpq_feed *mpq_sdmx_lookup_feed(struct dvb_demux_feed *feed)
+{
+ int i;
+ struct dvb_demux_feed *tmp;
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+
+ for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
+ tmp = mpq_demux->feeds[i].dvb_demux_feed;
+ if ((tmp->state == DMX_STATE_GO) &&
+ (tmp != feed) &&
+ (tmp->feed.ts.buffer.ringbuff ==
+ feed->feed.ts.buffer.ringbuff)) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: main feed pid=%d, secondary feed pid=%d\n",
+ __func__, tmp->pid, feed->pid);
+ return &mpq_demux->feeds[i];
+ }
+ }
+
+ return NULL;
+}
+
+static int mpq_sdmx_alloc_data_buf(struct mpq_feed *mpq_feed, size_t size)
+{
+ struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+ void *buf_base;
+ int ret;
+
+ mpq_feed->sdmx_buf_handle = ion_alloc(mpq_demux->ion_client,
+ size,
+ SZ_4K,
+ ION_HEAP(ION_QSECOM_HEAP_ID),
+ 0);
+ if (IS_ERR_OR_NULL(mpq_feed->sdmx_buf_handle)) {
+ ret = PTR_ERR(mpq_feed->sdmx_buf_handle);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate sdmx buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ buf_base = ion_map_kernel(mpq_demux->ion_client,
+ mpq_feed->sdmx_buf_handle);
+ if (IS_ERR_OR_NULL(buf_base)) {
+ ret = PTR_ERR(buf_base);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to map sdmx buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto failed_free_buf;
+ }
+
+ dvb_ringbuffer_init(&mpq_feed->sdmx_buf, buf_base, size);
+
+ return 0;
+
+failed_free_buf:
+ ion_free(mpq_demux->ion_client, mpq_feed->sdmx_buf_handle);
+ mpq_feed->sdmx_buf_handle = NULL;
+end:
+ return ret;
+}
+
+static int mpq_sdmx_free_data_buf(struct mpq_feed *mpq_feed)
+{
+ struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+
+ if (mpq_feed->sdmx_buf_handle) {
+ ion_unmap_kernel(mpq_demux->ion_client,
+ mpq_feed->sdmx_buf_handle);
+ mpq_feed->sdmx_buf.data = NULL;
+ ion_free(mpq_demux->ion_client,
+ mpq_feed->sdmx_buf_handle);
+ mpq_feed->sdmx_buf_handle = NULL;
+ }
+
+ return 0;
+}
+
+static int mpq_sdmx_init_metadata_buffer(struct mpq_demux *mpq_demux,
+ struct mpq_feed *feed, struct sdmx_buff_descr *metadata_buff_desc)
+{
+ void *metadata_buff_base;
+ ion_phys_addr_t temp;
+ int ret;
+
+ feed->metadata_buf_handle = ion_alloc(mpq_demux->ion_client,
+ SDMX_METADATA_BUFFER_SIZE,
+ SZ_4K,
+ ION_HEAP(ION_QSECOM_HEAP_ID),
+ 0);
+ if (IS_ERR_OR_NULL(feed->metadata_buf_handle)) {
+ ret = PTR_ERR(feed->metadata_buf_handle);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate metadata buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ metadata_buff_base = ion_map_kernel(mpq_demux->ion_client,
+ feed->metadata_buf_handle);
+ if (IS_ERR_OR_NULL(metadata_buff_base)) {
+ ret = PTR_ERR(metadata_buff_base);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to map metadata buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto failed_free_metadata_buf;
+ }
+
+ ret = ion_phys(mpq_demux->ion_client,
+ feed->metadata_buf_handle,
+ &temp,
+ &metadata_buff_desc->size);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to get physical address %d\n",
+ __func__, ret);
+ goto failed_unmap_metadata_buf;
+ }
+ metadata_buff_desc->base_addr = (void *)temp;
+
+ dvb_ringbuffer_init(&feed->metadata_buf, metadata_buff_base,
+ SDMX_METADATA_BUFFER_SIZE);
+
+ return 0;
+
+failed_unmap_metadata_buf:
+ ion_unmap_kernel(mpq_demux->ion_client, feed->metadata_buf_handle);
+failed_free_metadata_buf:
+ ion_free(mpq_demux->ion_client, feed->metadata_buf_handle);
+ feed->metadata_buf_handle = NULL;
+end:
+ return ret;
+}
+
+static int mpq_sdmx_terminate_metadata_buffer(struct mpq_feed *mpq_feed)
+{
+ struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+
+ if (mpq_feed->metadata_buf_handle) {
+ ion_unmap_kernel(mpq_demux->ion_client,
+ mpq_feed->metadata_buf_handle);
+ mpq_feed->metadata_buf.data = NULL;
+ ion_free(mpq_demux->ion_client,
+ mpq_feed->metadata_buf_handle);
+ mpq_feed->metadata_buf_handle = NULL;
+ }
+
+ return 0;
+}
+
+int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+ struct mpq_demux *mpq_demux;
+ struct mpq_feed *mpq_feed;
+ struct mpq_feed *main_rec_feed;
+
+ if (feed == NULL)
+ return -EINVAL;
+
+ mpq_demux = feed->demux->priv;
+
+ mutex_lock(&mpq_demux->mutex);
+ mpq_feed = feed->priv;
+
+ if (mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE) {
+ if (mpq_feed->filter_type == SDMX_RAW_FILTER)
+ main_rec_feed = mpq_sdmx_lookup_feed(feed);
+ else
+ main_rec_feed = NULL;
+
+ if (main_rec_feed) {
+ /* This feed is part of a recording filter */
+ MPQ_DVB_DBG_PRINT(
+ "%s: Removing raw pid %d from filter %d\n",
+ __func__, feed->pid,
+ mpq_feed->sdmx_filter_handle);
+ ret = sdmx_remove_raw_pid(
+ mpq_demux->sdmx_session_handle,
+ mpq_feed->sdmx_filter_handle, feed->pid);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: SDMX_remove_raw_pid failed. ret = %d\n",
+ __func__, ret);
+
+ /* If this feed that we are removing was set as primary,
+ * now other feeds should be set as primary
+ */
+ if (!mpq_feed->secondary_feed)
+ main_rec_feed->secondary_feed = 0;
+ } else {
+ MPQ_DVB_DBG_PRINT("%s: Removing filter %d, pid %d\n",
+ __func__, mpq_feed->sdmx_filter_handle,
+ feed->pid);
+ ret = sdmx_remove_filter(mpq_demux->sdmx_session_handle,
+ mpq_feed->sdmx_filter_handle);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: SDMX_remove_filter failed. ret = %d\n",
+ __func__, ret);
+ }
+
+ mpq_demux->sdmx_filter_count--;
+ mpq_feed->sdmx_filter_handle =
+ SDMX_INVALID_FILTER_HANDLE;
+ }
+
+ mpq_sdmx_close_session(mpq_demux);
+ }
+
+ if (mpq_dmx_is_video_feed(feed)) {
+ ret = mpq_dmx_terminate_video_feed(mpq_feed);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_terminate_video_feed failed. ret = %d\n",
+ __func__, ret);
+ }
+
+ if (mpq_feed->sdmx_buf_handle) {
+ wake_up_all(&mpq_feed->sdmx_buf.queue);
+ mpq_sdmx_free_data_buf(mpq_feed);
+ }
+
+ mpq_sdmx_terminate_metadata_buffer(mpq_feed);
+
+ mutex_unlock(&mpq_demux->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_terminate_feed);
int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
{
- struct mpq_demux *mpq_demux = feed->demux->priv;
-
if (mpq_dmx_is_video_feed(feed)) {
+ struct mpq_feed *mpq_feed;
struct mpq_video_feed_info *feed_data;
- spin_lock(&mpq_demux->feed_lock);
-
- if (feed->priv == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: invalid feed, feed->priv is NULL\n",
- __func__);
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- feed_data = feed->priv;
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
feed_data->fullness_wait_cancel = 0;
- spin_unlock(&mpq_demux->feed_lock);
-
return 0;
}
@@ -1531,8 +1981,6 @@
size_t required_space)
{
u32 free = mpq_streambuffer_data_free(sbuff);
- MPQ_DVB_DBG_PRINT("%s: stream buffer free = %d, required = %d\n",
- __func__, free, required_space);
/*
* For linear buffers, verify there's enough space for this TSP
@@ -1554,7 +2002,9 @@
struct mpq_demux *mpq_demux = feed->demux->priv;
struct mpq_streambuffer *sbuff = NULL;
struct mpq_video_feed_info *feed_data;
- int ret;
+ struct mpq_feed *mpq_feed;
+ int ret = 0;
+ int was_locked;
if (!mpq_dmx_is_video_feed(feed)) {
MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
@@ -1563,21 +2013,26 @@
return -EINVAL;
}
- spin_lock(&mpq_demux->feed_lock);
- if (feed->priv == NULL) {
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
+ if (mutex_is_locked(&mpq_demux->mutex)) {
+ was_locked = 1;
+ } else {
+ mutex_lock(&mpq_demux->mutex);
+ was_locked = 0;
}
- feed_data = feed->priv;
+
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
+
sbuff = feed_data->video_buffer;
if (sbuff == NULL) {
- spin_unlock(&mpq_demux->feed_lock);
+ if (!was_locked)
+ mutex_unlock(&mpq_demux->mutex);
MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n",
__func__);
return -EINVAL;
}
- if ((feed_data != NULL) &&
+ if ((feed_data->video_buffer != NULL) &&
(!feed_data->fullness_wait_cancel) &&
(!mpq_dmx_check_decoder_fullness(sbuff, required_space))) {
DEFINE_WAIT(__wait);
@@ -1585,17 +2040,16 @@
prepare_to_wait(&sbuff->raw_data.queue,
&__wait,
TASK_INTERRUPTIBLE);
-
- if ((feed->priv == NULL) ||
+ if (!feed_data->video_buffer ||
feed_data->fullness_wait_cancel ||
mpq_dmx_check_decoder_fullness(sbuff,
required_space))
break;
if (!signal_pending(current)) {
- spin_unlock(&mpq_demux->feed_lock);
+ mutex_unlock(&mpq_demux->mutex);
schedule();
- spin_lock(&mpq_demux->feed_lock);
+ mutex_lock(&mpq_demux->mutex);
continue;
}
@@ -1606,46 +2060,47 @@
}
if (ret < 0) {
- spin_unlock(&mpq_demux->feed_lock);
+ if (!was_locked)
+ mutex_unlock(&mpq_demux->mutex);
return ret;
}
- if ((feed->priv == NULL) || (feed_data->fullness_wait_cancel)) {
- spin_unlock(&mpq_demux->feed_lock);
+ if ((feed_data->fullness_wait_cancel) ||
+ (feed_data->video_buffer == NULL)) {
+ if (!was_locked)
+ mutex_unlock(&mpq_demux->mutex);
return -EINVAL;
}
- spin_unlock(&mpq_demux->feed_lock);
+ mutex_unlock(&mpq_demux->mutex);
return 0;
}
EXPORT_SYMBOL(mpq_dmx_decoder_fullness_wait);
int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
{
- struct mpq_demux *mpq_demux = feed->demux->priv;
-
if (mpq_dmx_is_video_feed(feed)) {
+ struct mpq_feed *mpq_feed;
struct mpq_video_feed_info *feed_data;
struct dvb_ringbuffer *video_buff;
- spin_lock(&mpq_demux->feed_lock);
-
- if (feed->priv == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: invalid feed, feed->priv is NULL\n",
- __func__);
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- feed_data = feed->priv;
-
- video_buff = &feed_data->video_buffer->raw_data;
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
feed_data->fullness_wait_cancel = 1;
- spin_unlock(&mpq_demux->feed_lock);
+ spin_lock(&feed_data->video_buffer_lock);
+ if (feed_data->video_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: video_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->video_buffer_lock);
+ return 0;
+ }
+
+ video_buff = &feed_data->video_buffer->raw_data;
wake_up_all(&video_buff->queue);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -1920,6 +2375,11 @@
struct dmx_data_ready *data)
{
size_t len = 0;
+ struct dmx_pts_dts_info *pts_dts;
+
+ pts_dts = meta_data->packet_type == DMX_PES_PACKET ?
+ &meta_data->info.pes.pts_dts_info :
+ &meta_data->info.framing.pts_dts_info;
data->data_length = 0;
data->buf.handle = packet->raw_data_handle;
@@ -1928,10 +2388,10 @@
feed_data->last_pkt_index, &len);
data->buf.offset = packet->raw_data_offset;
data->buf.len = packet->raw_data_len;
- data->buf.pts_exists = meta_data->info.framing.pts_dts_info.pts_exist;
- data->buf.pts = meta_data->info.framing.pts_dts_info.pts;
- data->buf.dts_exists = meta_data->info.framing.pts_dts_info.dts_exist;
- data->buf.dts = meta_data->info.framing.pts_dts_info.dts;
+ data->buf.pts_exists = pts_dts->pts_exist;
+ data->buf.pts = pts_dts->pts;
+ data->buf.dts_exists = pts_dts->dts_exist;
+ data->buf.dts = pts_dts->dts;
data->buf.tei_counter = feed_data->tei_errs;
data->buf.cont_err_counter = feed_data->continuity_errs;
data->buf.ts_packets_num = feed_data->ts_packets_num;
@@ -1959,6 +2419,7 @@
struct mpq_streambuffer *stream_buffer;
struct pes_packet_header *pes_header;
struct mpq_demux *mpq_demux;
+ struct mpq_feed *mpq_feed;
struct mpq_framing_pattern_lookup_results framing_res;
struct mpq_streambuffer_packet_header packet;
@@ -1976,18 +2437,28 @@
mpq_demux = feed->demux->priv;
- spin_lock(&mpq_demux->feed_lock);
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
- feed_data = feed->priv;
- if (unlikely(feed_data == NULL)) {
- spin_unlock(&mpq_demux->feed_lock);
+ /*
+ * spin-lock is taken to protect against manipulation of video
+ * output buffer by the API (terminate video feed, re-use of video
+ * buffers). Mutex on the video-feed cannot be held here
+ * since SW demux holds a spin-lock while calling write_to_decoder
+ */
+ spin_lock(&feed_data->video_buffer_lock);
+ stream_buffer = feed_data->video_buffer;
+
+ if (stream_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: video_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
ts_header = (const struct ts_packet_header *)buf;
- stream_buffer = feed_data->video_buffer;
-
pes_header = &feed_data->pes_header;
/* Make sure this TS packet has a payload and not scrambled */
@@ -1996,7 +2467,7 @@
(ts_header->adaptation_field_control == 2) ||
(ts_header->transport_scrambling_control)) {
/* continue to next packet */
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2028,7 +2499,7 @@
* otherwise the data is dropped
*/
if (!feed->pusi_seen) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0; /* drop and wait for next packets */
}
@@ -2055,7 +2526,7 @@
pes_header, buf,
&ts_payload_offset,
&bytes_avail)) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2063,7 +2534,7 @@
pes_header, buf,
&ts_payload_offset,
&bytes_avail)) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2072,7 +2543,7 @@
* then we are now at the PES payload data
*/
if (bytes_avail == 0) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2125,7 +2596,7 @@
* or equivalent is found. Otherwise the data is dropped.
*/
if (!(feed_data->found_sequence_header_pattern)) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2231,9 +2702,6 @@
feed->indexing_params.standard,
feed_data->last_framing_match_type);
if (is_video_frame == 1) {
- struct timespec curr_time, delta_time;
- u64 delta_time_ms;
-
mpq_dmx_write_pts_dts(feed_data,
&(meta_data.info.framing.pts_dts_info));
mpq_dmx_save_pts_dts(feed_data);
@@ -2248,33 +2716,7 @@
0, /* current write buffer handle */
&packet.raw_data_handle);
- curr_time = current_kernel_time();
- if (likely(mpq_demux->decoder_out_count)) {
- /* calculate time-delta between frame */
- delta_time = timespec_sub(curr_time,
- mpq_demux->decoder_out_last_time);
-
- delta_time_ms =
- ((u64)delta_time.tv_sec * MSEC_PER_SEC)
- + delta_time.tv_nsec / NSEC_PER_MSEC;
-
- mpq_demux->decoder_out_interval_sum +=
- (u32)delta_time_ms;
-
- mpq_demux->
- decoder_out_interval_average =
- mpq_demux->decoder_out_interval_sum /
- mpq_demux->decoder_out_count;
-
- if (delta_time_ms >
- mpq_demux->decoder_out_interval_max)
- mpq_demux->
- decoder_out_interval_max =
- delta_time_ms;
- }
-
- mpq_demux->decoder_out_last_time = curr_time;
- mpq_demux->decoder_out_count++;
+ mpq_dmx_update_decoder_stat(mpq_demux);
/*
* writing meta-data that includes
@@ -2328,7 +2770,7 @@
}
}
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2343,23 +2785,32 @@
struct mpq_streambuffer *stream_buffer;
struct pes_packet_header *pes_header;
struct mpq_demux *mpq_demux;
+ struct mpq_feed *mpq_feed;
int discontinuity_indicator = 0;
struct dmx_data_ready data;
mpq_demux = feed->demux->priv;
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
- spin_lock(&mpq_demux->feed_lock);
-
- feed_data = feed->priv;
- if (unlikely(feed_data == NULL)) {
- spin_unlock(&mpq_demux->feed_lock);
+ /*
+ * spin-lock is taken to protect against manipulation of video
+ * output buffer by the API (terminate video feed, re-use of video
+ * buffers). Mutex on the video-feed cannot be held here
+ * since SW demux holds a spin-lock while calling write_to_decoder
+ */
+ spin_lock(&feed_data->video_buffer_lock);
+ stream_buffer = feed_data->video_buffer;
+ if (stream_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: video_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
ts_header = (const struct ts_packet_header *)buf;
- stream_buffer = feed_data->video_buffer;
-
pes_header = &feed_data->pes_header;
/* Make sure this TS packet has a payload and not scrambled */
@@ -2368,7 +2819,7 @@
(ts_header->adaptation_field_control == 2) ||
(ts_header->transport_scrambling_control)) {
/* continue to next packet */
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2402,6 +2853,8 @@
meta_data.packet_type = DMX_PES_PACKET;
+ mpq_dmx_update_decoder_stat(mpq_demux);
+
if (mpq_streambuffer_pkt_write(
stream_buffer,
&packet,
@@ -2436,10 +2889,6 @@
}
/* Reset PES info */
- feed_data->pes_payload_address =
- (u32)stream_buffer->raw_data.data +
- stream_buffer->raw_data.pwrite;
-
feed->peslen = 0;
feed_data->pes_header_offset = 0;
feed_data->pes_header_left_bytes =
@@ -2454,7 +2903,7 @@
* otherwise the data is dropped
*/
if (!feed->pusi_seen) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0; /* drop and wait for next packets */
}
@@ -2481,7 +2930,7 @@
pes_header, buf,
&ts_payload_offset,
&bytes_avail)) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2489,7 +2938,7 @@
pes_header, buf,
&ts_payload_offset,
&bytes_avail)) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2498,7 +2947,7 @@
* then we are now at the PES payload data
*/
if (bytes_avail == 0) {
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2529,7 +2978,7 @@
feed->peslen += bytes_avail;
}
- spin_unlock(&mpq_demux->feed_lock);
+ spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2540,6 +2989,7 @@
struct mpq_demux *mpq_demux = feed->demux->priv;
struct mpq_video_feed_info *feed_data;
struct mpq_streambuffer *video_buff;
+ struct mpq_feed *mpq_feed;
if (!mpq_dmx_is_video_feed(feed)) {
MPQ_DVB_ERR_PRINT(
@@ -2549,20 +2999,13 @@
return -EINVAL;
}
- spin_lock(&mpq_demux->feed_lock);
+ mutex_lock(&mpq_demux->mutex);
- if (feed->priv == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: invalid feed, feed->priv is NULL\n",
- __func__);
- spin_unlock(&mpq_demux->feed_lock);
- return -EINVAL;
- }
-
- feed_data = feed->priv;
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
video_buff = feed_data->video_buffer;
if (!video_buff) {
- spin_unlock(&mpq_demux->feed_lock);
+ mutex_unlock(&mpq_demux->mutex);
return -EINVAL;
}
@@ -2592,7 +3035,7 @@
&dmx_buffer_status->read_offset,
&dmx_buffer_status->write_offset);
- spin_unlock(&mpq_demux->feed_lock);
+ mutex_unlock(&mpq_demux->mutex);
return 0;
}
@@ -2609,17 +3052,21 @@
}
EXPORT_SYMBOL(mpq_dmx_process_video_packet);
-int mpq_dmx_process_pcr_packet(
- struct dvb_demux_feed *feed,
- const u8 *buf)
+/*
+ * Extract the PCR field and discontinuity indicator from a TS packet buffer
+ * @buf: TSP buffer
+ * @pcr: returned PCR value
+ * @dci: returned discontinuity indicator
+ * Returns 1 if PCR was extracted, 0 otherwise.
+ */
+static int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci)
{
- u64 pcr;
- u64 stc;
- struct dmx_data_ready data;
- struct mpq_demux *mpq_demux = feed->demux->priv;
const struct ts_packet_header *ts_header;
const struct ts_adaptation_field *adaptation_field;
+ if (buf == NULL || pcr == NULL || dci == NULL)
+ return 0;
+
ts_header = (const struct ts_packet_header *)buf;
/* Make sure this TS packet has a adaptation field */
@@ -2636,16 +3083,32 @@
(!adaptation_field->PCR_flag))
return 0; /* 0 adaptation field or no PCR */
- pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25;
- pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17;
- pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9;
- pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1;
- pcr += adaptation_field->program_clock_reference_base_5;
- pcr *= 300;
- pcr +=
- (((u64)adaptation_field->program_clock_reference_ext_1) << 8) +
+ *pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25;
+ *pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17;
+ *pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9;
+ *pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1;
+ *pcr += adaptation_field->program_clock_reference_base_5;
+ *pcr *= 300;
+ *pcr += (((u64)adaptation_field->program_clock_reference_ext_1) << 8) +
adaptation_field->program_clock_reference_ext_2;
+ *dci = adaptation_field->discontinuity_indicator;
+
+ return 1;
+}
+
+int mpq_dmx_process_pcr_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ u64 stc;
+ struct dmx_data_ready data;
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+
+ if (0 == mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr,
+ &data.pcr.disc_indicator_set))
+ return 0;
+
/*
* When we play from front-end, we configure HW
* to output the extra timestamp, if we are playing
@@ -2663,12 +3126,1312 @@
}
data.data_length = 0;
- data.pcr.pcr = pcr;
data.pcr.stc = stc;
- data.pcr.disc_indicator_set = adaptation_field->discontinuity_indicator;
data.status = DMX_OK_PCR;
feed->data_ready_cb.ts(&feed->feed.ts, &data);
return 0;
}
EXPORT_SYMBOL(mpq_dmx_process_pcr_packet);
+
+int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
+ struct dmx_secure_mode *sec_mode)
+{
+ struct mpq_feed *mpq_feed;
+ struct mpq_demux *mpq_demux;
+ int ret;
+
+ if (!feed || !feed->priv || !sec_mode) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid parameters\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n",
+ __func__, sec_mode->pid,
+ sec_mode->is_secured,
+ sec_mode->key_ladder_id);
+
+ mpq_feed = feed->priv;
+ mpq_demux = mpq_feed->mpq_demux;
+
+ mutex_lock(&mpq_demux->mutex);
+
+ /*
+ * If secure demux is active, set the KL now,
+ * otherwise it will be set when secure-demux is started
+ * (when filtering starts).
+ */
+ if (mpq_demux->sdmx_session_handle !=
+ SDMX_INVALID_SESSION_HANDLE) {
+ if (sec_mode->is_secured) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: set key-ladder %d to PID %d\n",
+ __func__,
+ sec_mode->key_ladder_id,
+ sec_mode->pid);
+ ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
+ sec_mode->pid, sec_mode->key_ladder_id);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to set keyladder, ret=%d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+ } else {
+ MPQ_DVB_DBG_PRINT("%s: setting non-secure mode\n",
+ __func__);
+ ret = 0;
+ }
+ } else {
+ MPQ_DVB_DBG_PRINT("%s: SDMX not started yet\n", __func__);
+ ret = 0;
+ }
+
+ mutex_unlock(&mpq_demux->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_set_secure_mode);
+
+int mpq_sdmx_open_session(struct mpq_demux *mpq_demux)
+{
+ enum sdmx_status ret = SDMX_SUCCESS;
+ enum sdmx_proc_mode proc_mode;
+ enum sdmx_pkt_format pkt_format;
+
+ MPQ_DVB_DBG_PRINT("%s: ref_count %d\n",
+ __func__, mpq_demux->sdmx_session_ref_count);
+
+ if (mpq_demux->sdmx_session_ref_count) {
+ /* session is already open */
+ mpq_demux->sdmx_session_ref_count++;
+ return ret;
+ }
+
+ proc_mode = (mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) ?
+ SDMX_PUSH_MODE : SDMX_PULL_MODE;
+ MPQ_DVB_DBG_PRINT(
+ "%s: Proc mode = %s\n",
+ __func__, SDMX_PUSH_MODE == proc_mode ? "Push" : "Pull");
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0) {
+ pkt_format = SDMX_192_BYTE_PKT;
+ } else if (DMX_TSP_FORMAT_188 == mpq_demux->demux.tsp_format) {
+ pkt_format = SDMX_188_BYTE_PKT;
+ } else if (DMX_TSP_FORMAT_192_TAIL == mpq_demux->demux.tsp_format) {
+ pkt_format = SDMX_192_BYTE_PKT;
+ } else {
+ MPQ_DVB_ERR_PRINT("%s: invalid tsp format\n", __func__);
+ return -EINVAL;
+ }
+
+ MPQ_DVB_DBG_PRINT("%s: (%s) source, packet format: %d\n",
+ __func__,
+ (mpq_demux->source < DMX_SOURCE_DVR0) ?
+ "frontend" : "DVR", pkt_format);
+
+ /* open session and set configuration */
+ ret = sdmx_open_session(&mpq_demux->sdmx_session_handle);
+ if (ret != SDMX_SUCCESS) {
+ MPQ_DVB_ERR_PRINT("%s: Could not open session. ret=%d\n",
+ __func__ , ret);
+ return ret;
+ }
+
+ MPQ_DVB_DBG_PRINT("%s: new session_handle = %d\n",
+ __func__ , mpq_demux->sdmx_session_handle);
+
+ ret = sdmx_set_session_cfg(mpq_demux->sdmx_session_handle,
+ proc_mode,
+ SDMX_PKT_ENC_MODE,
+ pkt_format,
+ mpq_sdmx_scramble_odd,
+ mpq_sdmx_scramble_even);
+ if (ret != SDMX_SUCCESS) {
+ MPQ_DVB_ERR_PRINT("%s: Could not set session config. ret=%d\n",
+ __func__, ret);
+ sdmx_close_session(mpq_demux->sdmx_session_handle);
+ mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+ return -EINVAL;
+ }
+
+ mpq_demux->sdmx_process_count = 0;
+ mpq_demux->sdmx_process_time_sum = 0;
+ mpq_demux->sdmx_process_time_average = 0;
+ mpq_demux->sdmx_process_time_max = 0;
+ mpq_demux->sdmx_process_packets_sum = 0;
+ mpq_demux->sdmx_process_packets_average = 0;
+ mpq_demux->sdmx_process_packets_min = 0;
+
+ mpq_demux->sdmx_session_ref_count++;
+ return ret;
+}
+EXPORT_SYMBOL(mpq_sdmx_open_session);
+
+int mpq_sdmx_close_session(struct mpq_demux *mpq_demux)
+{
+ int ret = 0;
+ enum sdmx_status status;
+
+ MPQ_DVB_DBG_PRINT("%s: session_handle = %d, ref_count %d\n",
+ __func__,
+ mpq_demux->sdmx_session_handle,
+ mpq_demux->sdmx_session_ref_count);
+
+ if (!mpq_demux->sdmx_session_ref_count)
+ return -EINVAL;
+
+ if (mpq_demux->sdmx_session_ref_count == 1) {
+ status = sdmx_close_session(mpq_demux->sdmx_session_handle);
+ if (status != SDMX_SUCCESS) {
+ MPQ_DVB_ERR_PRINT("%s: sdmx_close_session failed %d\n",
+ __func__, status);
+ return -EINVAL;
+ }
+ mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+ }
+
+ mpq_demux->sdmx_session_ref_count--;
+
+ return ret;
+}
+EXPORT_SYMBOL(mpq_sdmx_close_session);
+
+static int mpq_sdmx_init_data_buffer(struct mpq_demux *mpq_demux,
+ struct mpq_feed *feed, u32 *num_buffers,
+ struct sdmx_buff_descr *buf_desc, enum sdmx_buf_mode *buf_mode)
+{
+ struct dvb_demux_feed *dvbdmx_feed = feed->dvb_demux_feed;
+ struct dvb_ringbuffer *buffer;
+ struct mpq_video_feed_info *feed_data = &feed->video_info;
+ ion_phys_addr_t addr;
+ struct ion_handle *sdmx_buff;
+ int ret;
+ int i;
+
+ *buf_mode = SDMX_RING_BUF;
+
+ if (mpq_dmx_is_video_feed(feed->dvb_demux_feed)) {
+ if (feed_data->buffer_desc.decoder_buffers_num > 1)
+ *buf_mode = SDMX_LINEAR_GROUP_BUF;
+ *num_buffers = feed_data->buffer_desc.decoder_buffers_num;
+
+ for (i = 0; i < *num_buffers; i++) {
+ ret = ion_phys(mpq_demux->ion_client,
+ feed_data->buffer_desc.ion_handle[i],
+ &addr, &buf_desc[i].size);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to get physical buffer address, ret=%d\n",
+ __func__, ret);
+ goto end;
+ }
+ buf_desc[i].base_addr = (void *)addr;
+ buf_desc[i].size = feed_data->buffer_desc.desc[i].size;
+ }
+ } else {
+ *num_buffers = 1;
+ if (mpq_dmx_is_sec_feed(dvbdmx_feed) ||
+ mpq_dmx_is_pcr_feed(dvbdmx_feed)) {
+ buffer = &feed->sdmx_buf;
+ sdmx_buff = feed->sdmx_buf_handle;
+ } else {
+ buffer = (struct dvb_ringbuffer *)
+ dvbdmx_feed->feed.ts.buffer.ringbuff;
+ sdmx_buff = dvbdmx_feed->feed.ts.buffer.priv_handle;
+ }
+
+ if (sdmx_buff == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid buffer allocation\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ ret = ion_phys(mpq_demux->ion_client, sdmx_buff, &addr,
+ &buf_desc[0].size);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to get physical buffer address, ret=%d\n",
+ __func__, ret);
+ goto end;
+ } else {
+ buf_desc[0].size = buffer->size;
+ buf_desc[0].base_addr = (void *)addr;
+ }
+
+ }
+ return 0;
+
+end:
+ return ret;
+}
+
+
+static int mpq_sdmx_filter_setup(struct mpq_demux *mpq_demux,
+ struct dvb_demux_feed *dvbdmx_feed)
+{
+ int ret = 0;
+ struct mpq_feed *feed;
+ struct mpq_feed *main_rec_feed;
+ struct sdmx_buff_descr metadata_buff_desc;
+ struct sdmx_buff_descr data_buff_desc[DMX_MAX_DECODER_BUFFER_NUM];
+ u32 data_buf_num = DMX_MAX_DECODER_BUFFER_NUM;
+ enum sdmx_buf_mode buf_mode;
+
+ feed = dvbdmx_feed->priv;
+
+ if (mpq_dmx_is_sec_feed(dvbdmx_feed)) {
+ feed->filter_type = SDMX_SECTION_FILTER;
+ MPQ_DVB_DBG_PRINT("%s: SDMX_SECTION_FILTER\n", __func__);
+ } else if (mpq_dmx_is_pcr_feed(dvbdmx_feed)) {
+ feed->filter_type = SDMX_PCR_FILTER;
+ MPQ_DVB_DBG_PRINT("%s: SDMX_PCR_FILTER\n", __func__);
+ } else if (mpq_dmx_is_video_feed(dvbdmx_feed)) {
+ feed->filter_type = SDMX_SEPARATED_PES_FILTER;
+ MPQ_DVB_DBG_PRINT("%s: SDMX_SEPARATED_PES_FILTER\n", __func__);
+ } else if (mpq_dmx_is_rec_feed(dvbdmx_feed)) {
+ feed->filter_type = SDMX_RAW_FILTER;
+ MPQ_DVB_DBG_PRINT("%s: SDMX_RAW_FILTER\n", __func__);
+ } else {
+ feed->filter_type = SDMX_PES_FILTER;
+ MPQ_DVB_DBG_PRINT("%s: SDMX_PES_FILTER\n", __func__);
+ }
+
+ /*
+ * Recording feed sdmx filter handle lookup:
+ * In case this is a recording filter with multiple feeds,
+ * this feed is either the first feed of a new recording filter,
+ * or it is another feed of an existing filter for which a filter was
+ * already opened with sdmx. In such case, we need to look up in the
+ * feed pool for a allocated feed with same output buffer (meaning they
+ * belong to the same filter) and to use the already allocated sdmx
+ * filter handle.
+ */
+ if (feed->filter_type == SDMX_RAW_FILTER)
+ main_rec_feed = mpq_sdmx_lookup_feed(dvbdmx_feed);
+ else
+ main_rec_feed = NULL;
+
+ /*
+ * If this PID is not part of existing recording filter,
+ * configure a new filter to SDMX.
+ */
+ if (!main_rec_feed) {
+ feed->secondary_feed = 0;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Adding new sdmx filter, pid %d\n",
+ __func__, dvbdmx_feed->pid);
+
+ /* Meta-data initialization,
+ * Recording filters do no need meta-data buffers.
+ */
+ if (mpq_dmx_is_rec_feed(dvbdmx_feed)) {
+ metadata_buff_desc.base_addr = 0;
+ metadata_buff_desc.size = 0;
+ } else {
+ ret = mpq_sdmx_init_metadata_buffer(mpq_demux, feed,
+ &metadata_buff_desc);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Failed to initialize metadata buffer. ret=%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+
+ ret = mpq_sdmx_init_data_buffer(mpq_demux, feed, &data_buf_num,
+ data_buff_desc, &buf_mode);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Failed to initialize data buffer. ret=%d\n",
+ __func__, ret);
+ mpq_sdmx_terminate_metadata_buffer(feed);
+ goto end;
+ }
+ ret = sdmx_add_filter(mpq_demux->sdmx_session_handle,
+ dvbdmx_feed->pid,
+ feed->filter_type,
+ &metadata_buff_desc,
+ buf_mode,
+ data_buf_num,
+ data_buff_desc,
+ &feed->sdmx_filter_handle);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: SDMX_add_filter failed. ret = %d\n",
+ __func__, ret);
+ ret = -ENODEV;
+ mpq_sdmx_terminate_metadata_buffer(feed);
+ goto end;
+ }
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: feed=0x%p, filter pid=%d, handle=%d, data buffer(s)=%d, size=%d\n",
+ __func__, feed, dvbdmx_feed->pid,
+ feed->sdmx_filter_handle,
+ data_buf_num, data_buff_desc[0].size);
+
+ mpq_demux->sdmx_filter_count++;
+ } else {
+ MPQ_DVB_DBG_PRINT(
+ "%s: Adding RAW pid to sdmx, pid %d\n",
+ __func__, dvbdmx_feed->pid);
+
+ feed->secondary_feed = 1;
+ feed->sdmx_filter_handle = main_rec_feed->sdmx_filter_handle;
+ ret = sdmx_add_raw_pid(mpq_demux->sdmx_session_handle,
+ feed->sdmx_filter_handle, dvbdmx_feed->pid);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to add raw pid, ret=%d\n",
+ __func__, ret);
+ ret = -ENODEV;
+ goto end;
+ }
+ }
+
+ /*
+ * If pid has a key ladder id associated, we need to
+ * set it to SDMX.
+ */
+ if (dvbdmx_feed->secure_mode.is_secured) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: set key-ladder %d to PID %d\n",
+ __func__,
+ dvbdmx_feed->secure_mode.key_ladder_id,
+ dvbdmx_feed->secure_mode.pid);
+ ret = sdmx_set_kl_ind(
+ mpq_demux->sdmx_session_handle,
+ dvbdmx_feed->secure_mode.pid,
+ dvbdmx_feed->secure_mode.key_ladder_id);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to set key ladder, ret=%d\n",
+ __func__, ret);
+ ret = -ENODEV;
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_feed *mpq_feed = feed->priv;
+
+ mutex_lock(&mpq_demux->mutex);
+
+ if (mpq_dmx_is_video_feed(feed)) {
+ ret = mpq_dmx_init_video_feed(mpq_feed);
+
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_init_video_feed failed, ret=%d\n",
+ __func__, ret);
+ goto init_mpq_feed_failed;
+ }
+ }
+
+ if (!mpq_sdmx_is_loaded()) {
+ /* nothing more to do */
+ mpq_feed->sdmx_buf_handle = NULL;
+ mpq_feed->metadata_buf_handle = NULL;
+ mpq_feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE;
+ mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+ mutex_unlock(&mpq_demux->mutex);
+ return ret;
+ }
+
+ /* Further initializations for secure demux */
+ ret = mpq_sdmx_open_session(mpq_demux);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_sdmx_open_session failed, ret=%d\n",
+ __func__, ret);
+
+ ret = -ENODEV;
+ goto init_mpq_feed_failed_free_video;
+ }
+
+ /* PCR and sections have internal buffer for SDMX */
+ if (mpq_dmx_is_pcr_feed(feed))
+ ret = mpq_sdmx_alloc_data_buf(mpq_feed,
+ SDMX_PCR_BUFFER_SIZE);
+ else if (mpq_dmx_is_sec_feed(feed))
+ ret = mpq_sdmx_alloc_data_buf(mpq_feed,
+ SDMX_SECTION_BUFFER_SIZE);
+ else
+ ret = 0;
+
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: init buffer failed, ret=%d\n",
+ __func__, ret);
+ goto init_mpq_feed_failed_free_sdmx;
+ }
+
+ ret = mpq_sdmx_filter_setup(mpq_demux, feed);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_sdmx_filter_setup failed, ret=%d\n",
+ __func__, ret);
+ goto init_mpq_feed_failed_free_data_buff;
+ }
+
+ mutex_unlock(&mpq_demux->mutex);
+ return 0;
+
+init_mpq_feed_failed_free_data_buff:
+ mpq_sdmx_free_data_buf(mpq_feed);
+init_mpq_feed_failed_free_sdmx:
+ mpq_sdmx_close_session(mpq_demux);
+init_mpq_feed_failed_free_video:
+ if (mpq_dmx_is_video_feed(feed))
+ mpq_dmx_terminate_video_feed(mpq_feed);
+init_mpq_feed_failed:
+ mutex_unlock(&mpq_demux->mutex);
+ return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_init_mpq_feed);
+
+static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
+ struct sdmx_filter_status *filter_sts,
+ struct mpq_feed *mpq_feed)
+{
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct mpq_video_feed_info *feed_data;
+ struct mpq_streambuffer *sbuff;
+
+ filter_sts->filter_handle = mpq_feed->sdmx_filter_handle;
+ filter_sts->metadata_fill_count =
+ dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+ filter_sts->metadata_write_offset = mpq_feed->metadata_buf.pwrite;
+ filter_sts->error_indicators = 0;
+ filter_sts->status_indicators = 0;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Filter meta-data buffer status: fill count = %d, write_offset = %d\n",
+ __func__, filter_sts->metadata_fill_count,
+ filter_sts->metadata_write_offset);
+
+ if (!mpq_dmx_is_video_feed(feed)) {
+ struct dvb_ringbuffer *buffer;
+
+ if (mpq_dmx_is_sec_feed(feed) ||
+ mpq_dmx_is_pcr_feed(feed)) {
+ buffer = (struct dvb_ringbuffer *)
+ &mpq_feed->sdmx_buf;
+ } else {
+ buffer = (struct dvb_ringbuffer *)
+ feed->feed.ts.buffer.ringbuff;
+ }
+
+ filter_sts->data_fill_count = dvb_ringbuffer_avail(buffer);
+ filter_sts->data_write_offset = buffer->pwrite;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Filter buffers status: fill count = %d, write_offset = %d\n",
+ __func__, filter_sts->data_fill_count,
+ filter_sts->data_write_offset);
+
+ return;
+ }
+
+ /* Video feed - decoder buffers */
+ feed_data = &mpq_feed->video_info;
+
+ spin_lock(&mpq_feed->video_info.video_buffer_lock);
+ sbuff = feed_data->video_buffer;
+ if (sbuff == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: video_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->video_buffer_lock);
+ return;
+ }
+
+ if (feed_data->buffer_desc.decoder_buffers_num > 1) {
+ /* linear mode */
+ filter_sts->data_fill_count = sbuff->pending_buffers_count;
+ filter_sts->data_write_offset =
+ sbuff->raw_data.pwrite /
+ sizeof(struct mpq_streambuffer_buffer_desc);
+ } else {
+ /* ring buffer mode */
+ filter_sts->data_fill_count =
+ mpq_streambuffer_data_avail(sbuff);
+ mpq_streambuffer_get_data_rw_offset(sbuff, NULL,
+ &filter_sts->data_write_offset);
+
+ }
+
+ spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Decoder buffers filter status: fill count = %d, write_offset = %d\n",
+ __func__, filter_sts->data_fill_count,
+ filter_sts->data_write_offset);
+}
+
+
+static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed,
+ struct dvb_demux_filter *f,
+ struct sdmx_metadata_header *header)
+{
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ int ret;
+ u8 neq = 0;
+ u8 xor;
+ u8 tmp;
+ int i;
+
+ for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+ tmp = DVB_RINGBUFFER_PEEK(&mpq_feed->sdmx_buf, i);
+ xor = f->filter.filter_value[i] ^ tmp;
+
+ if (f->maskandmode[i] & xor)
+ return 0;
+
+ neq |= f->maskandnotmode[i] & xor;
+ }
+
+ if (f->doneq && !neq)
+ return 0;
+
+ if (feed->demux->playback_mode == DMX_PB_MODE_PULL) {
+ int was_locked;
+
+ if (mutex_is_locked(&mpq_feed->mpq_demux->mutex)) {
+ mutex_unlock(&mpq_feed->mpq_demux->mutex);
+ was_locked = 1;
+ } else {
+ was_locked = 0;
+ }
+
+ ret = feed->demux->buffer_ctrl.sec(&f->filter,
+ header->payload_length);
+
+ if (was_locked)
+ mutex_lock(&mpq_feed->mpq_demux->mutex);
+
+ if (ret) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: buffer_ctrl.sec aborted\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ if (mpq_feed->sdmx_buf.pread + header->payload_length <
+ mpq_feed->sdmx_buf.size) {
+ feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread],
+ header->payload_length,
+ NULL, 0, &f->filter, DMX_OK);
+ } else {
+ int split = mpq_feed->sdmx_buf.size - mpq_feed->sdmx_buf.pread;
+ feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread],
+ split,
+ &mpq_feed->sdmx_buf.data[0],
+ header->payload_length - split,
+ &f->filter, DMX_OK);
+ }
+
+ return 0;
+}
+
+static int mpq_sdmx_check_ts_stall(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed,
+ struct sdmx_filter_status *sts,
+ size_t req,
+ int events_only)
+{
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ int ret;
+ int was_locked;
+
+ /*
+ * For PULL mode need to verify there is enough space for the dmxdev
+ * event. Also, if data buffer is full we want to stall until some
+ * data is removed from it to prevent calling the sdmx when it cannot
+ * output data to the still full buffer.
+ */
+ if (mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) {
+ MPQ_DVB_DBG_PRINT("%s: Stalling for events and %d bytes\n",
+ __func__, req);
+
+ if (mutex_is_locked(&mpq_demux->mutex)) {
+ mutex_unlock(&mpq_demux->mutex);
+ was_locked = 1;
+ } else {
+ was_locked = 0;
+ }
+
+ ret = mpq_demux->demux.buffer_ctrl.ts(&feed->feed.ts, req);
+ MPQ_DVB_DBG_PRINT("%s: stall result = %d\n",
+ __func__, ret);
+
+ if (was_locked)
+ mutex_lock(&mpq_demux->mutex);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Handle filter results for filters with no extra meta-data */
+static void mpq_sdmx_pes_filter_results(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed,
+ struct sdmx_filter_status *sts)
+{
+ int ret;
+ struct sdmx_metadata_header header;
+ struct dmx_data_ready data_event;
+ struct dmx_data_ready pes_event;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *)
+ feed->feed.ts.buffer.ringbuff;
+
+ if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+ goto pes_filter_check_overflow;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Meta: fill=%u, write=%u. Data: fill=%u, write=%u\n",
+ __func__, sts->metadata_fill_count, sts->metadata_write_offset,
+ sts->data_fill_count, sts->data_write_offset);
+
+ mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+
+ if ((0 == sts->metadata_fill_count) &&
+ (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) {
+ ssize_t free = dvb_ringbuffer_free(buf);
+ ret = 0;
+ if ((free + SZ_2K) < MAX_PES_LENGTH)
+ ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts,
+ free + SZ_2K, 0);
+ else
+ MPQ_DVB_ERR_PRINT(
+ "%s: Cannot stall when free space bigger than max PES size\n",
+ __func__);
+ if (ret) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_sdmx_check_ts_stall aborted\n",
+ __func__);
+ return;
+ }
+ }
+
+ while (sts->metadata_fill_count) {
+ if (dvb_ringbuffer_avail(&mpq_feed->metadata_buf) <
+ sizeof(header)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: metadata_fill_count is %d but actual buffer has less than %d bytes\n",
+ __func__,
+ sts->metadata_fill_count,
+ sizeof(header));
+ break;
+ }
+
+ dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
+ sizeof(header));
+ MPQ_DVB_DBG_PRINT(
+ "%s: metadata header: start=%u, length=%u\n",
+ __func__, header.payload_start, header.payload_length);
+ sts->metadata_fill_count -= sizeof(header);
+
+ /* Notify new data in buffer */
+ data_event.status = DMX_OK;
+ data_event.data_length = header.payload_length;
+ ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts,
+ data_event.data_length, 0);
+ if (ret) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_sdmx_check_ts_stall aborted\n",
+ __func__);
+ return;
+ }
+
+ feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+
+ /* Notify new complete PES */
+ pes_event.status = DMX_OK_PES_END;
+ pes_event.pes_end.actual_length = header.payload_length;
+ pes_event.pes_end.start_gap = 0;
+ pes_event.data_length = 0;
+
+ /* Parse error indicators - TODO: these should be per filter */
+ 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;
+ /* TODO: report these when SDMX returns them */
+ pes_event.pes_end.stc = 0;
+ pes_event.pes_end.tei_counter = 0;
+ pes_event.pes_end.cont_err_counter = 0;
+ pes_event.pes_end.ts_packets_num = 0;
+
+ ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, 0, 1);
+ if (ret) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_sdmx_check_ts_stall aborted\n",
+ __func__);
+ return;
+ }
+ feed->data_ready_cb.ts(&feed->feed.ts, &pes_event);
+ }
+
+pes_filter_check_overflow:
+ if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) &&
+ (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) {
+ MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__);
+ data_event.status = DMX_OVERRUN_ERROR;
+ data_event.data_length = 0;
+ feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+ }
+}
+
+static void mpq_sdmx_section_filter_results(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed,
+ struct sdmx_filter_status *sts)
+{
+ struct sdmx_metadata_header header;
+ struct dmx_data_ready event;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct dvb_demux_filter *f;
+ struct dmx_section_feed *sec = &feed->feed.sec;
+
+ /* Parse error indicators */
+ if (sts->error_indicators & SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL) {
+ 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);
+ }
+
+ if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
+ MPQ_DVB_ERR_PRINT("%s: internal section buffer overflowed!\n",
+ __func__);
+
+ if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+ return;
+
+ mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+ mpq_feed->sdmx_buf.pwrite = sts->data_write_offset;
+
+ while (sts->metadata_fill_count) {
+ dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
+ sizeof(header));
+ sts->metadata_fill_count -= sizeof(header);
+ MPQ_DVB_DBG_PRINT(
+ "%s: metadata header: start=%u, length=%u\n",
+ __func__, header.payload_start, header.payload_length);
+
+ f = feed->filter;
+ do {
+ if (mpq_sdmx_section_filtering(mpq_feed, f, &header))
+ return;
+ } while ((f = f->next) && sec->is_filtering);
+
+ DVB_RINGBUFFER_SKIP(&mpq_feed->sdmx_buf, header.payload_length);
+ }
+}
+
+static void mpq_sdmx_decoder_filter_results(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed,
+ struct sdmx_filter_status *sts)
+{
+ struct sdmx_metadata_header header;
+ int pes_header_offset;
+ struct ts_packet_header *ts_header;
+ struct ts_adaptation_field *ts_adapt;
+ struct pes_packet_header *pes_header;
+ u8 metadata_buf[MAX_SDMX_METADATA_LENGTH];
+ struct mpq_streambuffer *sbuf;
+ int ret;
+ int pes_cnt = 0;
+ struct dmx_data_ready data_event;
+
+ if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+ goto decoder_filter_check_overflow;
+
+ /* Update meta data buffer write pointer */
+ mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+
+ if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) &&
+ (sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) {
+ MPQ_DVB_DBG_PRINT("%s: Decoder stall...\n", __func__);
+
+ ret = mpq_dmx_decoder_fullness_wait(
+ mpq_feed->dvb_demux_feed, 0);
+ if (ret) {
+ /* we reach here if demuxing was aborted */
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_dmx_decoder_fullness_wait aborted\n",
+ __func__);
+ return;
+ }
+ }
+
+ while (sts->metadata_fill_count) {
+ struct mpq_streambuffer_packet_header packet;
+ struct mpq_adapter_video_meta_data meta_data;
+
+ pes_cnt++;
+ /* Read header & metadata */
+ dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header,
+ sizeof(header));
+ sts->metadata_fill_count -= sizeof(header);
+ MPQ_DVB_DBG_PRINT(
+ "%s: metadata header: start=%u, length=%u, metadata=%u\n",
+ __func__, header.payload_start, header.payload_length,
+ header.metadata_length);
+
+ /* Read actual metadata */
+ if (header.metadata_length < MAX_SDMX_METADATA_LENGTH)
+ dvb_ringbuffer_read(&mpq_feed->metadata_buf,
+ metadata_buf,
+ header.metadata_length);
+ else
+ MPQ_DVB_ERR_PRINT(
+ "%s: meta-data size=%d is too big for meta-data buffer=%d\n",
+ __func__, header.metadata_length,
+ MAX_SDMX_METADATA_LENGTH);
+ sts->metadata_fill_count -= header.metadata_length;
+
+ ts_header = (struct ts_packet_header *)&metadata_buf[0];
+ if (1 == ts_header->adaptation_field_control) {
+ ts_adapt = NULL;
+ pes_header_offset = sizeof(*ts_header);
+ } else {
+ ts_adapt = (struct ts_adaptation_field *)
+ &metadata_buf[sizeof(*ts_header)];
+ pes_header_offset = sizeof(*ts_header) + 1 +
+ ts_adapt->adaptation_field_length;
+ }
+ pes_header = (struct pes_packet_header *)
+ &metadata_buf[pes_header_offset];
+ meta_data.packet_type = DMX_PES_PACKET;
+ if (pes_header->pts_dts_flag & 0x2) {
+ meta_data.info.pes.pts_dts_info.pts_exist = 1;
+ meta_data.info.pes.pts_dts_info.pts =
+ ((u64)pes_header->pts_1 << 30) |
+ ((u64)pes_header->pts_2 << 22) |
+ ((u64)pes_header->pts_3 << 15) |
+ ((u64)pes_header->pts_4 << 7) |
+ (u64)pes_header->pts_5;
+ } else {
+ meta_data.info.pes.pts_dts_info.pts_exist = 0;
+ }
+
+ if (pes_header->pts_dts_flag & 0x1) {
+ meta_data.info.pes.pts_dts_info.dts_exist = 1;
+ meta_data.info.pes.pts_dts_info.dts =
+ ((u64)pes_header->dts_1 << 30) |
+ ((u64)pes_header->dts_2 << 22) |
+ ((u64)pes_header->dts_3 << 15) |
+ ((u64)pes_header->dts_4 << 7) |
+ (u64)pes_header->dts_5;
+ } else {
+ meta_data.info.pes.pts_dts_info.dts_exist = 0;
+ }
+
+ spin_lock(&mpq_feed->video_info.video_buffer_lock);
+ sbuf = mpq_feed->video_info.video_buffer;
+ if (sbuf == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: video_buffer released\n",
+ __func__);
+ spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+ return;
+ }
+
+ packet.raw_data_len = header.payload_length;
+ packet.user_data_len = sizeof(meta_data);
+ mpq_streambuffer_get_buffer_handle(sbuf, 0,
+ &packet.raw_data_handle);
+ mpq_streambuffer_get_data_rw_offset(sbuf,
+ NULL, &packet.raw_data_offset);
+ ret = mpq_streambuffer_data_write_deposit(sbuf,
+ header.payload_length);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_streambuffer_data_write_deposit failed. ret=%d\n",
+ __func__, ret);
+ }
+ mpq_dmx_update_decoder_stat(mpq_demux);
+ mpq_streambuffer_pkt_write(sbuf, &packet, (u8 *)&meta_data);
+
+ if (generate_es_events) {
+ struct dmx_data_ready data;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data, &mpq_feed->video_info,
+ sbuf, &data);
+ MPQ_DVB_DBG_PRINT("%s: Notify ES Event\n", __func__);
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ }
+
+ spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+ }
+
+decoder_filter_check_overflow:
+ if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) &&
+ (sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) {
+ MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__);
+ data_event.status = DMX_OVERRUN_ERROR;
+ data_event.data_length = 0;
+ mpq_feed->dvb_demux_feed->data_ready_cb.ts(
+ &mpq_feed->dvb_demux_feed->feed.ts, &data_event);
+ }
+}
+
+static void mpq_sdmx_pcr_filter_results(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed,
+ struct sdmx_filter_status *sts)
+{
+ int ret;
+ struct sdmx_metadata_header header;
+ struct dmx_data_ready data;
+ struct dvb_ringbuffer *rbuff = &mpq_feed->sdmx_buf;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ u8 buf[TS_PACKET_HEADER_LENGTH + MAX_TSP_ADAPTATION_LENGTH +
+ TIMESTAMP_LEN];
+ size_t stc_len = 0;
+
+ if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
+ MPQ_DVB_ERR_PRINT("%s: internal PCR buffer overflowed!\n",
+ __func__);
+
+ /* MPQ_TODO: Parse rest of error indicators ? */
+
+ if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+ return;
+
+ if (DMX_TSP_FORMAT_192_TAIL == mpq_demux->demux.tsp_format)
+ stc_len = 4;
+
+ mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+ rbuff->pwrite = sts->data_write_offset;
+
+ while (sts->metadata_fill_count) {
+ dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
+ sizeof(header));
+ MPQ_DVB_DBG_PRINT(
+ "%s: metadata header: start=%u, length=%u\n",
+ __func__, header.payload_start, header.payload_length);
+ sts->metadata_fill_count -= sizeof(header);
+
+ dvb_ringbuffer_read(rbuff, buf, header.payload_length);
+
+ if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr,
+ &data.pcr.disc_indicator_set)) {
+
+ if (stc_len) {
+ data.pcr.stc =
+ buf[header.payload_length-2] << 16;
+ data.pcr.stc +=
+ buf[header.payload_length-3] << 8;
+ data.pcr.stc += buf[header.payload_length-4];
+ /* convert from 105.47 KHZ to 27MHz */
+ data.pcr.stc *= 256;
+ } else {
+ data.pcr.stc = 0;
+ }
+
+ data.data_length = 0;
+ data.status = DMX_OK_PCR;
+ ret = mpq_sdmx_check_ts_stall(
+ mpq_demux, mpq_feed, sts, 0, 1);
+ if (ret) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_sdmx_check_ts_stall aborted\n",
+ __func__);
+ return;
+ }
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ }
+ }
+}
+
+static void mpq_sdmx_raw_filter_results(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed,
+ struct sdmx_filter_status *sts)
+{
+ int ret;
+ ssize_t new_data;
+ struct dmx_data_ready data_event;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *)
+ feed->feed.ts.buffer.ringbuff;
+
+ if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+ goto raw_filter_check_overflow;
+
+ new_data = sts->data_write_offset -
+ buf->pwrite;
+ if (new_data < 0)
+ new_data += buf->size;
+
+ ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts,
+ new_data + feed->demux->ts_packet_size, 0);
+ if (ret) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_sdmx_check_ts_stall aborted\n",
+ __func__);
+ return;
+ }
+
+ data_event.status = DMX_OK;
+ data_event.data_length = new_data;
+ feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+ MPQ_DVB_DBG_PRINT("%s: Callback DMX_OK, size=%d\n",
+ __func__, data_event.data_length);
+
+raw_filter_check_overflow:
+ if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) &&
+ (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) {
+ MPQ_DVB_DBG_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__);
+ data_event.status = DMX_OVERRUN_ERROR;
+ data_event.data_length = 0;
+ feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+ }
+}
+
+static void mpq_sdmx_process_results(struct mpq_demux *mpq_demux)
+{
+ int i;
+ int j;
+ struct sdmx_filter_status *sts;
+ struct mpq_feed *mpq_feed;
+
+ for (i = 0; i < mpq_demux->sdmx_filter_count; i++) {
+ /*
+ * MPQ_TODO: review lookup optimization
+ * Can have the related mpq_feed index already associated with
+ * the filter status.
+ */
+ sts = &mpq_demux->filters_status[i];
+ MPQ_DVB_DBG_PRINT(
+ "%s: Filter: handle=%d, status=0x%x, errors=0x%x\n",
+ __func__, sts->filter_handle, sts->status_indicators,
+ sts->error_indicators);
+ MPQ_DVB_DBG_PRINT("%s: Metadata fill count=%d (write=%d)\n",
+ __func__, sts->metadata_fill_count,
+ sts->metadata_write_offset);
+ MPQ_DVB_DBG_PRINT("%s: Data fill count=%d (write=%d)\n",
+ __func__, sts->data_fill_count, sts->data_write_offset);
+
+ for (j = 0; j < MPQ_MAX_DMX_FILES; j++) {
+ mpq_feed = &mpq_demux->feeds[j];
+ if ((mpq_feed->dvb_demux_feed->state == DMX_STATE_GO) &&
+ (sts->filter_handle ==
+ mpq_feed->sdmx_filter_handle) &&
+ (!mpq_feed->secondary_feed))
+ break;
+ }
+
+ if (j == MPQ_MAX_DMX_FILES)
+ continue;
+
+ if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
+ MPQ_DVB_ERR_PRINT(
+ "%s: meta-data buff for pid %d overflowed!\n",
+ __func__, mpq_feed->dvb_demux_feed->pid);
+
+ switch (mpq_feed->filter_type) {
+ case SDMX_PCR_FILTER:
+ mpq_sdmx_pcr_filter_results(mpq_demux, mpq_feed, sts);
+ break;
+ case SDMX_PES_FILTER:
+ mpq_sdmx_pes_filter_results(mpq_demux, mpq_feed,
+ sts);
+ break;
+ case SDMX_SEPARATED_PES_FILTER:
+ mpq_sdmx_decoder_filter_results(mpq_demux, mpq_feed,
+ sts);
+ break;
+ case SDMX_SECTION_FILTER:
+ mpq_sdmx_section_filter_results(mpq_demux, mpq_feed,
+ sts);
+ break;
+ case SDMX_RAW_FILTER:
+ mpq_sdmx_raw_filter_results(mpq_demux, mpq_feed, sts);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int mpq_sdmx_process(struct mpq_demux *mpq_demux,
+ struct sdmx_buff_descr *input,
+ u32 fill_count,
+ u32 read_offset)
+{
+ struct sdmx_filter_status *sts;
+ struct mpq_feed *mpq_feed;
+ u8 flags = 0; /* MPQ_TODO: EOS handling */
+ u32 errors;
+ u32 status;
+ u32 prev_read_offset;
+ u32 prev_fill_count;
+ enum sdmx_status sdmx_res;
+ int i;
+ int filter_index = 0;
+ int bytes_read;
+ struct timespec process_start_time;
+ struct timespec process_end_time;
+
+ mutex_lock(&mpq_demux->mutex);
+
+ /*
+ * All active filters may get totally closed and therefore
+ * sdmx session may get terminated, in such case nothing to process
+ */
+ if (mpq_demux->sdmx_session_handle == SDMX_INVALID_SESSION_HANDLE) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: sdmx filters aborted, filter-count %d, session %d\n",
+ __func__, mpq_demux->sdmx_filter_count,
+ mpq_demux->sdmx_session_handle);
+ mutex_unlock(&mpq_demux->mutex);
+ return 0;
+ }
+
+ /* Build up to date filter status array */
+ for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
+ mpq_feed = &mpq_demux->feeds[i];
+ if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
+ && (mpq_feed->dvb_demux_feed->state == DMX_STATE_GO)
+ && (!mpq_feed->secondary_feed)) {
+ sts = &mpq_demux->filters_status[filter_index];
+ mpq_sdmx_prepare_filter_status(mpq_demux, sts,
+ mpq_feed);
+ filter_index++;
+ }
+ }
+
+ /* Sanity check */
+ if (filter_index != mpq_demux->sdmx_filter_count) {
+ mutex_unlock(&mpq_demux->mutex);
+ MPQ_DVB_ERR_PRINT(
+ "%s: Updated %d SDMX filters status but should be %d\n",
+ __func__, filter_index, mpq_demux->sdmx_filter_count);
+ return -ERESTART;
+ }
+
+ MPQ_DVB_DBG_PRINT(
+ "\n\n%s: Before SDMX_process: input read_offset=%u, fill count=%u\n",
+ __func__, read_offset, fill_count);
+
+ process_start_time = current_kernel_time();
+
+ prev_read_offset = read_offset;
+ prev_fill_count = fill_count;
+ sdmx_res = sdmx_process(mpq_demux->sdmx_session_handle, flags, input,
+ &fill_count, &read_offset, &errors, &status,
+ mpq_demux->sdmx_filter_count, mpq_demux->filters_status);
+
+ process_end_time = current_kernel_time();
+ mpq_dmx_update_sdmx_stat(mpq_demux, prev_fill_count,
+ &process_start_time, &process_end_time);
+
+ bytes_read = prev_fill_count - fill_count;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: SDMX result=%d, input_fill_count=%u, read_offset=%u, read %d bytes from input, status=0x%X, errors=0x%X\n",
+ __func__, sdmx_res, fill_count, read_offset, bytes_read,
+ status, errors);
+
+ if ((sdmx_res == SDMX_SUCCESS) ||
+ (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE)) {
+ if (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE)
+ MPQ_DVB_DBG_PRINT("%s: SDMX stalled for PULL mode\n",
+ __func__);
+
+ mpq_sdmx_process_results(mpq_demux);
+ } else {
+ MPQ_DVB_ERR_PRINT(
+ "%s: SDMX Process returned %d\n",
+ __func__, sdmx_res);
+ }
+
+ mutex_unlock(&mpq_demux->mutex);
+
+ return bytes_read;
+}
+EXPORT_SYMBOL(mpq_sdmx_process);
+
+static int mpq_sdmx_write(struct mpq_demux *mpq_demux,
+ struct ion_handle *input_handle,
+ const char *buf,
+ size_t count)
+{
+ struct sdmx_buff_descr buf_desc;
+ struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+ mpq_demux->demux.dmx.dvr_input.ringbuff;
+ ion_phys_addr_t phys_addr;
+ u32 read_offset;
+ size_t len;
+ int ret;
+
+ if (mpq_demux == NULL || input_handle == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = ion_phys(mpq_demux->ion_client, input_handle, &phys_addr, &len);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Failed to obtain physical address of input buffer. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ buf_desc.base_addr = (void *)phys_addr;
+ buf_desc.size = rbuf->size;
+ read_offset = rbuf->pread;
+
+ return mpq_sdmx_process(mpq_demux, &buf_desc, count, read_offset);
+}
+
+int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count)
+{
+ struct dvb_demux *dvb_demux;
+ struct mpq_demux *mpq_demux;
+
+ if (demux == NULL)
+ return -EINVAL;
+
+ dvb_demux = demux->priv;
+ mpq_demux = dvb_demux->priv;
+
+ if (mpq_sdmx_is_loaded()) {
+ /* route through secure demux */
+ return mpq_sdmx_write(mpq_demux,
+ demux->dvr_input.priv_handle,
+ buf,
+ count);
+ } else {
+ /* route through sw filter */
+ dvb_dmx_swfilter_format(dvb_demux, buf, count,
+ dvb_demux->tsp_format);
+ if (signal_pending(current))
+ return -EINTR;
+ return count;
+ }
+}
+EXPORT_SYMBOL(mpq_dmx_write);
+
+int mpq_sdmx_is_loaded(void)
+{
+ return mpq_bypass_sdmx ? 0 : mpq_dmx_info.secure_demux_app_loaded;
+}
+EXPORT_SYMBOL(mpq_sdmx_is_loaded);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index c0d5412..2c2420b 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -21,12 +21,11 @@
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "mpq_adapter.h"
-
+#include "mpq_sdmx.h"
/* Max number open() request can be done on demux device */
#define MPQ_MAX_DMX_FILES 128
-
/**
* TSIF alias name length
*/
@@ -35,80 +34,6 @@
#define MPQ_MAX_FOUND_PATTERNS 5
/**
- * struct mpq_demux - mpq demux information
- * @demux: The dvb_demux instance used by mpq_demux
- * @dmxdev: The dmxdev instance used by mpq_demux
- * @fe_memory: Handle of front-end memory source to mpq_demux
- * @source: The current source connected to the demux
- * @is_initialized: Indicates whether this demux device was
- * initialized or not.
- * @ion_client: ION demux client used to allocate memory from ION.
- * @feed_lock: Lock used to protect against private feed data
- * @hw_notification_interval: Notification interval in msec,
- * exposed in debugfs.
- * @hw_notification_min_interval: Minimum notification internal in msec,
- * exposed in debugfs.
- * @hw_notification_count: Notification count, exposed in debugfs.
- * @hw_notification_size: Notification size in bytes, exposed in debugfs.
- * @hw_notification_min_size: Minimum notification size in bytes,
- * exposed in debugfs.
- * @decoder_drop_count: Accumulated number of bytes dropped due to decoder
- * buffer fullness, exposed in debugfs.
- * @decoder_out_count: Counter incremeneted for each video frame output by
- * demux, exposed in debugfs.
- * @decoder_out_interval_sum: Sum of intervals (msec) holding the time between
- * two successive video frames output, exposed in debugfs.
- * @decoder_out_interval_average: Average interval (msec) between two
- * successive video frames output, exposed in debugfs.
- * @decoder_out_interval_max: Max interval (msec) between two
- * successive video frames output, exposed in debugfs.
- * @decoder_ts_errors: Counter for number of decoder packets with TEI bit
- * set, exposed in debugfs.
- * @decoder_out_last_time: Time of last video frame output.
- * @last_notification_time: Time of last HW notification.
- */
-struct mpq_demux {
- struct dvb_demux demux;
- struct dmxdev dmxdev;
- struct dmx_frontend fe_memory;
- dmx_source_t source;
- int is_initialized;
- struct ion_client *ion_client;
- spinlock_t feed_lock;
-
- /* debug-fs */
- u32 hw_notification_interval;
- u32 hw_notification_min_interval;
- u32 hw_notification_count;
- u32 hw_notification_size;
- u32 hw_notification_min_size;
- u32 decoder_drop_count;
- u32 decoder_out_count;
- u32 decoder_out_interval_sum;
- u32 decoder_out_interval_average;
- u32 decoder_out_interval_max;
- u32 decoder_ts_errors;
- struct timespec decoder_out_last_time;
- struct timespec last_notification_time;
-};
-
-/**
- * mpq_dmx_init - initialization and registration function of
- * single MPQ demux device
- *
- * @adapter: The adapter to register mpq_demux to
- * @mpq_demux: The mpq demux to initialize
- *
- * Every HW pluging need to provide implementation of such
- * function that will be called for each demux device on the
- * module initialization. The function mpq_demux_plugin_init
- * should be called during the HW plugin module initialization.
- */
-typedef int (*mpq_dmx_init)(
- struct dvb_adapter *mpq_adapter,
- struct mpq_demux *demux);
-
-/**
* struct ts_packet_header - Transport packet header
* as defined in MPEG2 transport stream standard.
*/
@@ -307,9 +232,12 @@
/*
* mpq_video_feed_info - private data used for video feed.
*
- * @plugin_data: Underlying plugin's own private data.
* @video_buffer: Holds the streamer buffer shared with
* the decoder for feeds having the data going to the decoder.
+ * @video_buffer_lock: Lock protecting against video output buffer.
+ * The lock protects against API calls to manipulate the output buffer
+ * (initialize, free, re-use buffers) and dvb-sw demux parsing the video
+ * data through mpq_dmx_process_video_packet().
* @buffer_desc: Holds decoder buffer(s) information used for stream buffer.
* @pes_header: Used for feeds that output data to decoder,
* holds PES header of current processed PES.
@@ -319,8 +247,6 @@
* pes header.
* @fullness_wait_cancel: Flag used to signal to abort waiting for
* decoder's fullness.
- * @pes_payload_address: Used for feeds that output data to decoder,
- * holds current PES payload start address.
* @stream_interface: The ID of the video stream interface registered
* with this stream buffer.
* @patterns: pointer to the framing patterns to look for.
@@ -361,13 +287,12 @@
* a new elementary stream data event.
*/
struct mpq_video_feed_info {
- void *plugin_data;
struct mpq_streambuffer *video_buffer;
+ spinlock_t video_buffer_lock;
struct mpq_decoder_buffers_desc buffer_desc;
struct pes_packet_header pes_header;
u32 pes_header_left_bytes;
u32 pes_header_offset;
- u32 pes_payload_address;
int fullness_wait_cancel;
enum mpq_adapter_stream_if stream_interface;
const struct mpq_framing_pattern_lookup_params *patterns;
@@ -393,6 +318,141 @@
};
/**
+ * mpq feed object - mpq common plugin feed information
+ *
+ * @dvb_demux_feed: Back pointer to dvb demux level feed object
+ * @mpq_demux: Pointer to common mpq demux object
+ * @plugin_priv: Plugin specific private data
+ * @sdmx_filter_handle: Secure demux filter handle. Recording feed may share
+ * same filter handle
+ * @secondary_feed: Specifies if this feed shares filter handle with
+ * other feeds
+ * @metadata_buf: Ring buffer object for managing the metadata buffer
+ * @metadata_buf_handle: Allocation handle for the metadata buffer
+ * @sdmx_buf: Ring buffer object for intermediate output data from the sdmx
+ * @sdmx_buf_handle: Allocation handle for the sdmx intermediate data buffer
+ * @video_info: Video feed specific information
+ */
+struct mpq_feed {
+ struct dvb_demux_feed *dvb_demux_feed;
+ struct mpq_demux *mpq_demux;
+ void *plugin_priv;
+
+ /* Secure demux related */
+ int sdmx_filter_handle;
+ int secondary_feed;
+ enum sdmx_filter filter_type;
+ struct dvb_ringbuffer metadata_buf;
+ struct ion_handle *metadata_buf_handle;
+
+ struct dvb_ringbuffer sdmx_buf;
+ struct ion_handle *sdmx_buf_handle;
+
+ struct mpq_video_feed_info video_info;
+};
+
+/**
+ * struct mpq_demux - mpq demux information
+ * @demux: The dvb_demux instance used by mpq_demux
+ * @dmxdev: The dmxdev instance used by mpq_demux
+ * @fe_memory: Handle of front-end memory source to mpq_demux
+ * @source: The current source connected to the demux
+ * @is_initialized: Indicates whether this demux device was
+ * initialized or not.
+ * @ion_client: ION demux client used to allocate memory from ION.
+ * @mutex: Lock used to protect against private feed data
+ * @feeds: mpq common feed object pool
+ * @filters_status: Array holding buffers status for each secure demux filter.
+ * Used before each call to sdmx_process() to build up to date state.
+ * @sdmx_session_handle: Secure demux open session handle
+ * @sdmx_filter_count: Number of active secure demux filters
+ * @plugin_priv: Underlying plugin's own private data
+ * @hw_notification_interval: Notification interval in msec,
+ * exposed in debugfs.
+ * @hw_notification_min_interval: Minimum notification internal in msec,
+ * exposed in debugfs.
+ * @hw_notification_count: Notification count, exposed in debugfs.
+ * @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @hw_notification_min_size: Minimum notification size in bytes,
+ * exposed in debugfs.
+ * @decoder_drop_count: Accumulated number of bytes dropped due to decoder
+ * buffer fullness, exposed in debugfs.
+ * @decoder_out_count: Counter incremeneted for each video frame output by
+ * demux, exposed in debugfs.
+ * @decoder_out_interval_sum: Sum of intervals (msec) holding the time between
+ * two successive video frames output, exposed in debugfs.
+ * @decoder_out_interval_average: Average interval (msec) between two
+ * successive video frames output, exposed in debugfs.
+ * @decoder_out_interval_max: Max interval (msec) between two
+ * successive video frames output, exposed in debugfs.
+ * @decoder_ts_errors: Counter for number of decoder packets with TEI bit
+ * set, exposed in debugfs.
+ * @sdmx_process_count: Total number of times sdmx_process is called.
+ * @sdmx_process_time_sum: Total time sdmx_process takes.
+ * @sdmx_process_time_average: Average time sdmx_process takes.
+ * @sdmx_process_time_max: Max time sdmx_process takes.
+ * @sdmx_process_packets_sum: Total packets number sdmx_process handled.
+ * @sdmx_process_packets_average: Average packets number sdmx_process handled.
+ * @sdmx_process_packets_min: Minimum packets number sdmx_process handled.
+ * @decoder_out_last_time: Time of last video frame output.
+ * @last_notification_time: Time of last HW notification.
+ */
+struct mpq_demux {
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_memory;
+ dmx_source_t source;
+ int is_initialized;
+ struct ion_client *ion_client;
+ struct mutex mutex;
+ struct mpq_feed feeds[MPQ_MAX_DMX_FILES];
+ struct sdmx_filter_status filters_status[MPQ_MAX_DMX_FILES];
+ int sdmx_session_handle;
+ int sdmx_session_ref_count;
+ int sdmx_filter_count;
+ void *plugin_priv;
+
+ /* debug-fs */
+ u32 hw_notification_interval;
+ u32 hw_notification_min_interval;
+ u32 hw_notification_count;
+ u32 hw_notification_size;
+ u32 hw_notification_min_size;
+ u32 decoder_drop_count;
+ u32 decoder_out_count;
+ u32 decoder_out_interval_sum;
+ u32 decoder_out_interval_average;
+ u32 decoder_out_interval_max;
+ u32 decoder_ts_errors;
+ u32 sdmx_process_count;
+ u32 sdmx_process_time_sum;
+ u32 sdmx_process_time_average;
+ u32 sdmx_process_time_max;
+ u32 sdmx_process_packets_sum;
+ u32 sdmx_process_packets_average;
+ u32 sdmx_process_packets_min;
+
+ struct timespec decoder_out_last_time;
+ struct timespec last_notification_time;
+};
+
+/**
+ * mpq_dmx_init - initialization and registration function of
+ * single MPQ demux device
+ *
+ * @adapter: The adapter to register mpq_demux to
+ * @mpq_demux: The mpq demux to initialize
+ *
+ * Every HW pluging need to provide implementation of such
+ * function that will be called for each demux device on the
+ * module initialization. The function mpq_demux_plugin_init
+ * should be called during the HW plugin module initialization.
+ */
+typedef int (*mpq_dmx_init)(
+ struct dvb_adapter *mpq_adapter,
+ struct mpq_demux *demux);
+
+/**
* mpq_demux_plugin_init - Initialize demux devices and register
* them to the dvb adapter.
*
@@ -454,36 +514,7 @@
* The function unmaps the buffer from kernel memory only if the buffer
* was not allocated with secure flag.
*/
-int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
- void *priv_handle);
-
-/**
- * mpq_dmx_init_video_feed - Initializes video feed
- * used to pass data to decoder directly.
- *
- * @feed: The feed used for the video TS packets
- *
- * Return error code.
- *
- * If the underlying plugin wishes to perform SW PES assmebly
- * for the video data and stream it to the decoder, it should
- * call this function when video feed is initialized before
- * using mpq_dmx_process_video_packet.
- *
- * The function allocates mpq_video_feed_info and saves in
- * feed->priv.
- */
-int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed);
-
-/**
- * mpq_dmx_terminate_video_feed - Free private data of
- * video feed allocated in mpq_dmx_init_video_feed
- *
- * @feed: The feed used for the video TS packets
- *
- * Return error code.
- */
-int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed);
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux, void *priv_handle);
/**
* mpq_dmx_decoder_fullness_init - Initialize waiting
@@ -634,6 +665,36 @@
}
/**
+ * mpq_dmx_is_sec_feed - Returns whether this is a section feed
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is a section feed, 0 otherwise.
+ */
+static inline int mpq_dmx_is_sec_feed(struct dvb_demux_feed *feed)
+{
+ return (feed->type == DMX_TYPE_SEC);
+}
+
+/**
+ * mpq_dmx_is_rec_feed - Returns whether this is a recording feed
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is recording feed, 0 otherwise.
+ */
+static inline int mpq_dmx_is_rec_feed(struct dvb_demux_feed *feed)
+{
+ if (feed->type != DMX_TYPE_TS)
+ return 0;
+
+ if (feed->ts_type & (TS_DECODER | TS_PAYLOAD_ONLY))
+ return 0;
+
+ return 1;
+}
+
+/**
* mpq_dmx_init_hw_statistics -
* Extend dvb-demux debugfs with HW statistics.
*
@@ -641,7 +702,6 @@
*/
void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux);
-
/**
* mpq_dmx_update_hw_statistics -
* Update dvb-demux debugfs with HW notification statistics.
@@ -650,5 +710,96 @@
*/
void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux);
+/**
+ * mpq_dmx_set_secure_mode - Handles set secure mode command from demux device
+ *
+ * @feed: The feed to set its secure mode
+ * @sec_mode: Secure mode details (key ladder info)
+ *
+ * Return error code
+*/
+int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
+ struct dmx_secure_mode *secure_mode);
+
+/**
+ * mpq_sdmx_open_session - Handle the details of opening a new secure demux
+ * session for the specified mpq demux instance. Multiple calls to this
+ * is allowed, reference counting is managed to open it only when needed.
+ *
+ * @mpq_demux: mpq demux instance
+ *
+ * Return error code
+ */
+int mpq_sdmx_open_session(struct mpq_demux *mpq_demux);
+
+/**
+ * mpq_sdmx_close_session - Closes secure demux session. The session
+ * is closed only if reference counter of the session reaches 0.
+ *
+ * @mpq_demux: mpq demux instance
+ *
+ * Return error code
+ */
+int mpq_sdmx_close_session(struct mpq_demux *mpq_demux);
+
+/**
+ * mpq_dmx_init_mpq_feed - Initialize an mpq feed object
+ * The function allocates mpq_feed object and saves in the dvb_demux_feed
+ * priv field.
+ *
+ * @feed: A dvb demux level feed parent object
+ *
+ * Return error code
+ */
+int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_terminate_feed - Destroy an mpq feed object
+ *
+ * @feed: A dvb demux level feed parent object
+ *
+ * Return error code
+ */
+int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_write - demux write() function implementation.
+ *
+ * A wrapper function used for writing new data into the demux via DVR.
+ * It checks where new data should actually go, the secure demux or the normal
+ * dvb demux software demux.
+ *
+ * @demux: demux interface
+ * @buf: input buffer
+ * @count: number of data bytes in input buffer
+ *
+ * Return number of bytes processed or error code
+ */
+int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count);
+
+/**
+ * mpq_sdmx_process - Perform demuxing process on the specified input buffer
+ * in the secure demux instance
+ *
+ * @mpq_demux: mpq demux instance
+ * @input: input buffer descriptor
+ * @fill_count: number of data bytes in input buffer that can be read
+ * @read_offset: offset in buffer for reading
+ *
+ * Return number of bytes read or error code
+ */
+int mpq_sdmx_process(struct mpq_demux *mpq_demux,
+ struct sdmx_buff_descr *input,
+ u32 fill_count,
+ u32 read_offset);
+
+/**
+ * mpq_sdmx_loaded - Returns 1 if secure demux application is loaded,
+ * 0 otherwise. This function should be used to determine whether or not
+ * processing should take place in the SDMX.
+ */
+int mpq_sdmx_is_loaded(void);
+
+
#endif /* _MPQ_DMX_PLUGIN_COMMON_H */
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index 3ad3d21..c0f7085 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -440,24 +440,17 @@
*/
feed->pusi_seen = 0;
- /*
- * For video PES, data is tunneled to the decoder,
- * initialize tunneling and pes parsing.
- */
- if (mpq_dmx_is_video_feed(feed)) {
- ret = mpq_dmx_init_video_feed(feed);
+ ret = mpq_dmx_init_mpq_feed(feed);
+ if (ret < 0) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_dmx_init_mpq_feed failed(%d)\n",
+ __func__,
+ ret);
- if (ret < 0) {
- MPQ_DVB_DBG_PRINT(
- "%s: mpq_dmx_init_video_feed failed(%d)\n",
- __func__,
- ret);
+ if (mpq_demux->source < DMX_SOURCE_DVR0)
+ mpq_tsif_dmx_stop(mpq_demux);
- if (mpq_demux->source < DMX_SOURCE_DVR0)
- mpq_tsif_dmx_stop(mpq_demux);
-
- return ret;
- }
+ return ret;
}
return ret;
@@ -489,12 +482,7 @@
return -EINVAL;
}
- /*
- * For video PES, data is tunneled to the decoder,
- * terminate tunnel and pes parsing.
- */
- if (mpq_dmx_is_video_feed(feed))
- mpq_dmx_terminate_video_feed(feed);
+ mpq_dmx_terminate_feed(feed);
if (mpq_demux->source < DMX_SOURCE_DVR0) {
/* Source from TSIF, need to configure TSIF hardware */
@@ -655,21 +643,13 @@
mpq_demux->demux.start_feed = mpq_tsif_dmx_start_filtering;
mpq_demux->demux.stop_feed = mpq_tsif_dmx_stop_filtering;
mpq_demux->demux.write_to_decoder = mpq_tsif_dmx_write_to_decoder;
-
- mpq_demux->demux.decoder_fullness_init =
- mpq_dmx_decoder_fullness_init;
-
- mpq_demux->demux.decoder_fullness_wait =
- mpq_dmx_decoder_fullness_wait;
-
+ mpq_demux->demux.decoder_fullness_init = mpq_dmx_decoder_fullness_init;
+ mpq_demux->demux.decoder_fullness_wait = mpq_dmx_decoder_fullness_wait;
mpq_demux->demux.decoder_fullness_abort =
mpq_dmx_decoder_fullness_abort;
-
- mpq_demux->demux.decoder_buffer_status =
- mpq_dmx_decoder_buffer_status;
-
- mpq_demux->demux.reuse_decoder_buffer =
- mpq_dmx_reuse_decoder_buffer;
+ mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status;
+ mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
+ mpq_demux->demux.set_secure_mode = NULL;
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 0eee8f3..be11ff4 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
+#include <linux/vmalloc.h>
#include <mach/msm_tspp.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
@@ -116,6 +117,13 @@
u32 buffer_count;
/*
+ * Array holding the IDs of the TSPP buffer descriptors in the
+ * current aggregate, in order to release these descriptors at
+ * the end of processing.
+ */
+ int *aggregate_ids;
+
+ /*
* Holds PIDs of allocated TSPP filters along with
* how many feeds are opened on same PID.
*/
@@ -222,6 +230,59 @@
}
/**
+ * Demux TS packets from TSPP by secure-demux.
+ * The fucntion assumes the buffer is physically contiguous
+ * and that TSPP descriptors are continuous in memory.
+ *
+ * @tsif: The TSIF interface to process its packets
+ * @channel_id: the TSPP output pipe with the TS packets
+ */
+static void mpq_dmx_tspp_aggregated_process(int tsif, int channel_id)
+{
+ const struct tspp_data_descriptor *tspp_data_desc;
+ struct mpq_demux *mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+ struct sdmx_buff_descr input;
+ size_t aggregate_len = 0;
+ size_t aggregate_count = 0;
+ phys_addr_t buff_start_addr;
+ phys_addr_t buff_current_addr;
+ int i;
+
+ while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
+ if (0 == aggregate_count)
+ buff_current_addr = tspp_data_desc->phys_base;
+ mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[aggregate_count] =
+ tspp_data_desc->id;
+ aggregate_len += tspp_data_desc->size;
+ aggregate_count++;
+ mpq_demux->hw_notification_size +=
+ tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
+ }
+
+ if (!aggregate_count)
+ return;
+
+ buff_start_addr = mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base;
+ input.base_addr = (void *)buff_start_addr;
+ input.size = mpq_dmx_tspp_info.tsif[tsif].buffer_count *
+ TSPP_DESCRIPTOR_SIZE;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Processing %d descriptors: %d bytes at start address 0x%x, read offset %d\n",
+ __func__, aggregate_count, aggregate_len,
+ (unsigned int)input.base_addr,
+ buff_current_addr - buff_start_addr);
+
+ mpq_sdmx_process(mpq_demux, &input, aggregate_len,
+ buff_current_addr - buff_start_addr);
+
+ for (i = 0; i < aggregate_count; i++)
+ tspp_release_buffer(0, channel_id,
+ mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[i]);
+}
+
+
+/**
* Demux thread function handling data from specific TSIF.
*
* @arg: TSIF number
@@ -270,27 +331,40 @@
mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
mpq_demux->hw_notification_size = 0;
- /*
- * Go through all filled descriptors
- * and perform demuxing on them
- */
- while ((tspp_data_desc = tspp_get_buffer(0, channel_id))
- != NULL) {
- notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
- mpq_demux->hw_notification_size += notif_size;
+ if (MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC != allocation_mode &&
+ mpq_sdmx_is_loaded())
+ pr_err_once(
+ "%s: TSPP Allocation mode does not support secure demux.\n",
+ __func__);
- for (j = 0; j < notif_size; j++)
- dvb_dmx_swfilter_packet(
- &mpq_demux->demux,
- ((u8 *)tspp_data_desc->virt_base) +
- j * TSPP_RAW_TTS_SIZE,
- ((u8 *)tspp_data_desc->virt_base) +
- j * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+ if (MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC == allocation_mode &&
+ mpq_sdmx_is_loaded()) {
+ mpq_dmx_tspp_aggregated_process(tsif, channel_id);
+ } else {
/*
- * Notify TSPP that the buffer
- * is no longer needed
+ * Go through all filled descriptors
+ * and perform demuxing on them
*/
- tspp_release_buffer(0, channel_id, tspp_data_desc->id);
+ while ((tspp_data_desc = tspp_get_buffer(0, channel_id))
+ != NULL) {
+ notif_size = tspp_data_desc->size /
+ TSPP_RAW_TTS_SIZE;
+ mpq_demux->hw_notification_size += notif_size;
+
+ for (j = 0; j < notif_size; j++)
+ dvb_dmx_swfilter_packet(
+ &mpq_demux->demux,
+ ((u8 *)tspp_data_desc->virt_base) +
+ j * TSPP_RAW_TTS_SIZE,
+ ((u8 *)tspp_data_desc->virt_base) +
+ j * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+ /*
+ * Notify TSPP that the buffer
+ * is no longer needed
+ */
+ tspp_release_buffer(0, channel_id,
+ tspp_data_desc->id);
+ }
}
if (mpq_demux->hw_notification_size &&
@@ -523,8 +597,8 @@
(void *)tsif,
tspp_channel_timeout);
- /* register allocater and provide allocation function
- * that allocates from continous memory so that we can have
+ /* register allocator and provide allocation function
+ * that allocates from contiguous memory so that we can have
* big notification size, smallest descriptor, and still provide
* TZ with single big buffer based on notification size.
*/
@@ -739,7 +813,7 @@
struct mpq_demux *mpq_demux = feed->demux->priv;
MPQ_DVB_DBG_PRINT(
- "%s(%d) executed\n",
+ "%s(pid=%d) executed\n",
__func__,
feed->pid);
@@ -770,24 +844,16 @@
*/
feed->pusi_seen = 0;
- /*
- * For video PES, data is tunneled to the decoder,
- * initialize tunneling and pes parsing.
- */
- if (mpq_dmx_is_video_feed(feed)) {
- ret = mpq_dmx_init_video_feed(feed);
+ ret = mpq_dmx_init_mpq_feed(feed);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_init_mpq_feed failed(%d)\n",
+ __func__,
+ ret);
+ if (mpq_demux->source < DMX_SOURCE_DVR0)
+ mpq_tspp_dmx_remove_channel(feed);
- if (ret < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: mpq_dmx_init_video_feed failed(%d)\n",
- __func__,
- ret);
-
- if (mpq_demux->source < DMX_SOURCE_DVR0)
- mpq_tspp_dmx_remove_channel(feed);
-
- return ret;
- }
+ return ret;
}
return 0;
@@ -797,18 +863,12 @@
{
int ret = 0;
struct mpq_demux *mpq_demux = feed->demux->priv;
-
MPQ_DVB_DBG_PRINT(
"%s(%d) executed\n",
__func__,
feed->pid);
- /*
- * For video PES, data is tunneled to the decoder,
- * terminate tunnel and pes parsing.
- */
- if (mpq_dmx_is_video_feed(feed))
- mpq_dmx_terminate_video_feed(feed);
+ mpq_dmx_terminate_feed(feed);
if (mpq_demux->source < DMX_SOURCE_DVR0) {
/* source from TSPP, need to configure tspp pipe */
@@ -951,21 +1011,13 @@
mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder;
-
- mpq_demux->demux.decoder_fullness_init =
- mpq_dmx_decoder_fullness_init;
-
- mpq_demux->demux.decoder_fullness_wait =
- mpq_dmx_decoder_fullness_wait;
-
+ mpq_demux->demux.decoder_fullness_init = mpq_dmx_decoder_fullness_init;
+ mpq_demux->demux.decoder_fullness_wait = mpq_dmx_decoder_fullness_wait;
mpq_demux->demux.decoder_fullness_abort =
mpq_dmx_decoder_fullness_abort;
-
- mpq_demux->demux.decoder_buffer_status =
- mpq_dmx_decoder_buffer_status;
-
- mpq_demux->demux.reuse_decoder_buffer =
- mpq_dmx_reuse_decoder_buffer;
+ mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status;
+ mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
+ mpq_demux->demux.set_secure_mode = mpq_dmx_set_secure_mode;
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
@@ -986,7 +1038,7 @@
mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
-
+ mpq_demux->dmxdev.demux->write = mpq_dmx_write;
result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
if (result < 0) {
MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
@@ -1018,6 +1070,20 @@
mpq_dmx_tspp_info.tsif[i].buffer_count =
TSPP_BUFFER_COUNT(tspp_out_buffer_size);
+ mpq_dmx_tspp_info.tsif[i].aggregate_ids =
+ vzalloc(mpq_dmx_tspp_info.tsif[i].buffer_count *
+ sizeof(int));
+ if (NULL == mpq_dmx_tspp_info.tsif[i].aggregate_ids) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Failed to allocate memory for buffer descriptors aggregation\n",
+ __func__);
+ for (j = 0; j < i; j++) {
+ kthread_stop(mpq_dmx_tspp_info.tsif[j].thread);
+ vfree(mpq_dmx_tspp_info.tsif[j].aggregate_ids);
+ mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
+ }
+ return -ENOMEM;
+ }
mpq_dmx_tspp_info.tsif[i].channel_ref = 0;
mpq_dmx_tspp_info.tsif[i].buff_index = 0;
mpq_dmx_tspp_info.tsif[i].ch_mem_heap_handle = NULL;
@@ -1042,8 +1108,11 @@
mpq_dmx_tspp_info.tsif[i].name);
if (IS_ERR(mpq_dmx_tspp_info.tsif[i].thread)) {
+ vfree(mpq_dmx_tspp_info.tsif[i].aggregate_ids);
+
for (j = 0; j < i; j++) {
kthread_stop(mpq_dmx_tspp_info.tsif[j].thread);
+ vfree(mpq_dmx_tspp_info.tsif[j].aggregate_ids);
mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
}
@@ -1067,6 +1136,7 @@
for (i = 0; i < TSIF_COUNT; i++) {
kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
+ vfree(mpq_dmx_tspp_info.tsif[i].aggregate_ids);
mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
}
}
@@ -1098,6 +1168,8 @@
MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC)
mpq_dmx_channel_mem_free(i);
}
+ if (mpq_dmx_tspp_info.tsif[i].aggregate_ids)
+ vfree(mpq_dmx_tspp_info.tsif[i].aggregate_ids);
mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
index 4211d6c..21483ee 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
@@ -126,6 +126,7 @@
mpq_demux->demux.decoder_fullness_abort = NULL;
mpq_demux->demux.decoder_buffer_status = NULL;
mpq_demux->demux.reuse_decoder_buffer = NULL;
+ mpq_demux->demux.set_secure_mode = NULL;
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
diff --git a/drivers/media/dvb/mpq/demux/mpq_sdmx.c b/drivers/media/dvb/mpq/demux/mpq_sdmx.c
new file mode 100644
index 0000000..0f91930
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_sdmx.c
@@ -0,0 +1,928 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "qseecom_kernel.h"
+#include "mpq_sdmx.h"
+
+static struct qseecom_handle *sdmx_qseecom_handles[SDMX_MAX_SESSIONS];
+static struct mutex sdmx_lock[SDMX_MAX_SESSIONS];
+
+#define QSEECOM_ALIGN_SIZE 0x40
+#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
+#define QSEECOM_ALIGN(x) \
+ ((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
+
+enum sdmx_cmd_id {
+ SDMX_OPEN_SESSION_CMD,
+ SDMX_CLOSE_SESSION_CMD,
+ SDMX_SET_SESSION_CFG_CMD,
+ SDMX_ADD_FILTER_CMD,
+ SDMX_REMOVE_FILTER_CMD,
+ SDMX_SET_KL_IDX_CMD,
+ SDMX_ADD_RAW_PID_CMD,
+ SDMX_REMOVE_RAW_PID_CMD,
+ SDMX_PROCESS_CMD,
+ SDMX_GET_DBG_COUNTERS_CMD,
+ SDMX_RESET_DBG_COUNTERS_CMD,
+ SDMX_GET_VERSION_CMD
+};
+
+struct sdmx_proc_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u8 flags;
+ struct sdmx_buff_descr in_buf_descr;
+ u32 inp_fill_cnt;
+ u32 in_rd_offset;
+ u32 num_filters;
+ struct sdmx_filter_status filters_status[];
+};
+
+struct sdmx_proc_rsp {
+ enum sdmx_status ret;
+ u32 inp_fill_cnt;
+ u32 in_rd_offset;
+ u32 err_indicators;
+ u32 status_indicators;
+};
+
+struct sdmx_open_ses_req {
+ enum sdmx_cmd_id cmd_id;
+};
+
+struct sdmx_open_ses_rsp {
+ enum sdmx_status ret;
+ u32 session_handle;
+};
+
+struct sdmx_close_ses_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+};
+
+struct sdmx_close_ses_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_ses_cfg_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ enum sdmx_proc_mode process_mode;
+ enum sdmx_inp_mode input_mode;
+ enum sdmx_pkt_format packet_len;
+ u8 odd_scramble_bits;
+ u8 even_scramble_bits;
+};
+
+struct sdmx_ses_cfg_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_set_kl_ind_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u32 pid;
+ u32 kl_index;
+};
+
+struct sdmx_set_kl_ind_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_add_filt_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u32 pid;
+ enum sdmx_filter filter_type;
+ struct sdmx_buff_descr meta_data_buf;
+ enum sdmx_buf_mode buffer_mode;
+ u32 num_data_bufs;
+ struct sdmx_buff_descr data_bufs[];
+};
+
+struct sdmx_add_filt_rsp {
+ enum sdmx_status ret;
+ u32 filter_handle;
+};
+
+struct sdmx_rem_filt_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u32 filter_handle;
+};
+
+struct sdmx_rem_filt_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_add_raw_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u32 filter_handle;
+ u32 pid;
+};
+
+struct sdmx_add_raw_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_rem_raw_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u32 filter_handle;
+ u32 pid;
+};
+
+struct sdmx_rem_raw_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_get_counters_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+ u32 num_filters;
+};
+
+struct sdmx_get_counters_rsp {
+ enum sdmx_status ret;
+ struct sdmx_session_dbg_counters session_counters;
+ u32 num_filters;
+ struct sdmx_filter_dbg_counters filter_counters[];
+};
+
+struct sdmx_rst_counters_req {
+ enum sdmx_cmd_id cmd_id;
+ u32 session_handle;
+};
+
+struct sdmx_rst_counters_rsp {
+ enum sdmx_status ret;
+};
+
+struct sdmx_get_version_req {
+ enum sdmx_cmd_id cmd_id;
+};
+
+struct sdmx_get_version_rsp {
+ enum sdmx_status ret;
+ int32_t version;
+};
+
+static void get_cmd_rsp_buffers(int handle_index,
+ void **cmd,
+ int *cmd_len,
+ void **rsp,
+ int *rsp_len)
+{
+ *cmd = sdmx_qseecom_handles[handle_index]->sbuf;
+
+ if (*cmd_len & QSEECOM_ALIGN_MASK)
+ *cmd_len = QSEECOM_ALIGN(*cmd_len);
+
+ *rsp = sdmx_qseecom_handles[handle_index]->sbuf + *cmd_len;
+
+ if (*rsp_len & QSEECOM_ALIGN_MASK)
+ *rsp_len = QSEECOM_ALIGN(*rsp_len);
+
+}
+
+/*
+ * Returns version of secure-demux app.
+ *
+ * @session_handle: Returned instance handle. Must not be NULL.
+ * Return error code
+ */
+int sdmx_get_version(int session_handle, int32_t *version)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_get_version_req *cmd;
+ struct sdmx_get_version_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+ (version == NULL))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_get_version_req);
+ rsp_len = sizeof(struct sdmx_get_version_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_GET_VERSION_CMD;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+ *version = rsp->version;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+
+}
+EXPORT_SYMBOL(sdmx_get_version);
+
+/*
+ * Initializes a new secure demux instance and returns a handle of the instance.
+ *
+ * @session_handle: handle of a secure demux instance to get its version.
+ * Return the version if successfull or an error code.
+ */
+int sdmx_open_session(int *session_handle)
+{
+ int res, cmd_len, rsp_len;
+ enum sdmx_status ret, version_ret;
+ struct sdmx_open_ses_req *cmd;
+ struct sdmx_open_ses_rsp *rsp;
+ struct qseecom_handle *qseecom_handle = NULL;
+ int32_t version;
+
+ /* Input validation */
+ if (session_handle == NULL)
+ return SDMX_STATUS_GENERAL_FAILURE;
+
+ /* Start the TZ app */
+ res = qseecom_start_app(&qseecom_handle, "securemm", 4096);
+
+ if (res < 0)
+ return SDMX_STATUS_GENERAL_FAILURE;
+
+ cmd_len = sizeof(struct sdmx_open_ses_req);
+ rsp_len = sizeof(struct sdmx_open_ses_rsp);
+
+ /* Get command and response buffers */
+ cmd = (struct sdmx_open_ses_req *)qseecom_handle->sbuf;
+
+ if (cmd_len & QSEECOM_ALIGN_MASK)
+ cmd_len = QSEECOM_ALIGN(cmd_len);
+
+ rsp = (struct sdmx_open_ses_rsp *)qseecom_handle->sbuf + cmd_len;
+
+ if (rsp_len & QSEECOM_ALIGN_MASK)
+ rsp_len = QSEECOM_ALIGN(rsp_len);
+
+ /* Will be later overridden by SDMX response */
+ *session_handle = SDMX_INVALID_SESSION_HANDLE;
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_OPEN_SESSION_CMD;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(qseecom_handle, (void *)cmd, cmd_len,
+ (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ qseecom_shutdown_app(&qseecom_handle);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ /* Parse response struct */
+ *session_handle = rsp->session_handle;
+
+ /* Initialize handle and mutex */
+ sdmx_qseecom_handles[*session_handle] = qseecom_handle;
+ mutex_init(&sdmx_lock[*session_handle]);
+ ret = rsp->ret;
+
+ /* Get and print the app version */
+ version_ret = sdmx_get_version(*session_handle, &version);
+ if (SDMX_SUCCESS == version_ret)
+ pr_info("TZ SDMX version is %x.%x\n", version >> 8,
+ version & 0xFF);
+ else
+ pr_err("Error reading TZ SDMX version\n");
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_open_session);
+
+/*
+ * Closes a secure demux instance.
+ *
+ * @session_handle: handle of a secure demux instance to close.
+ * Return error code
+ */
+int sdmx_close_session(int session_handle)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_close_ses_req *cmd;
+ struct sdmx_close_ses_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_close_ses_req);
+ rsp_len = sizeof(struct sdmx_close_ses_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_CLOSE_SESSION_CMD;
+ cmd->session_handle = session_handle;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ /* Shutdown the TZ app (or at least free the current handle) */
+ res = qseecom_shutdown_app(&sdmx_qseecom_handles[session_handle]);
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ sdmx_qseecom_handles[session_handle] = NULL;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_close_session);
+
+/*
+ * Configures an open secure demux instance.
+ *
+ * @session_handle: secure demux instance
+ * @proc_mode: Defines secure demux's behavior in case of output
+ * buffer overflow.
+ * @inp_mode: Defines the input encryption settings.
+ * @pkt_format: TS packet length in input buffer.
+ * @odd_scramble_bits: Value of the scramble bits indicating the ODD key.
+ * @even_scramble_bits: Value of the scramble bits indicating the EVEN key.
+ * Return error code
+ */
+int sdmx_set_session_cfg(int session_handle,
+ enum sdmx_proc_mode proc_mode,
+ enum sdmx_inp_mode inp_mode,
+ enum sdmx_pkt_format pkt_format,
+ u8 odd_scramble_bits,
+ u8 even_scramble_bits)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_ses_cfg_req *cmd;
+ struct sdmx_ses_cfg_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_ses_cfg_req);
+ rsp_len = sizeof(struct sdmx_ses_cfg_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_SET_SESSION_CFG_CMD;
+ cmd->session_handle = session_handle;
+ cmd->process_mode = proc_mode;
+ cmd->input_mode = inp_mode;
+ cmd->packet_len = pkt_format;
+ cmd->odd_scramble_bits = odd_scramble_bits;
+ cmd->even_scramble_bits = even_scramble_bits;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_set_session_cfg);
+
+/*
+ * Creates a new secure demux filter and returns a filter handle
+ *
+ * @session_handle: secure demux instance
+ * @pid: pid to filter
+ * @filter_type: type of filtering
+ * @meta_data_buf: meta data buffer descriptor
+ * @data_buf_mode: data buffer mode (ring/linear)
+ * @num_data_bufs: number of data buffers (use 1 for a ring buffer)
+ * @data_bufs: data buffers descriptors array
+ * @filter_handle: returned filter handle
+ *
+ * Return error code
+ */
+int sdmx_add_filter(int session_handle,
+ u16 pid,
+ enum sdmx_filter filterype,
+ struct sdmx_buff_descr *meta_data_buf,
+ enum sdmx_buf_mode d_buf_mode,
+ u32 num_data_bufs,
+ struct sdmx_buff_descr *data_bufs,
+ int *filter_handle)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_add_filt_req *cmd;
+ struct sdmx_add_filt_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+ (filter_handle == NULL))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_add_filt_req)
+ + num_data_bufs * sizeof(struct sdmx_buff_descr);
+ rsp_len = sizeof(struct sdmx_add_filt_rsp);
+
+ /* Will be later overridden by SDMX response */
+ *filter_handle = SDMX_INVALID_FILTER_HANDLE;
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_ADD_FILTER_CMD;
+ cmd->session_handle = session_handle;
+ cmd->pid = (u32)pid;
+ cmd->filter_type = filterype;
+ if (meta_data_buf != NULL)
+ memcpy(&(cmd->meta_data_buf), meta_data_buf,
+ sizeof(struct sdmx_buff_descr));
+ else
+ memset(&(cmd->meta_data_buf), 0,
+ sizeof(struct sdmx_buff_descr));
+
+ cmd->buffer_mode = d_buf_mode;
+ cmd->num_data_bufs = num_data_bufs;
+ memcpy(cmd->data_bufs, data_bufs,
+ num_data_bufs * sizeof(struct sdmx_buff_descr));
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ /* Parse response struct */
+ *filter_handle = rsp->filter_handle;
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_add_filter);
+
+/*
+ * Removes a secure demux filter
+ *
+ * @session_handle: secure demux instance
+ * @filter_handle: filter handle to remove
+ *
+ * Return error code
+ */
+int sdmx_remove_filter(int session_handle, int filter_handle)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_rem_filt_req *cmd;
+ struct sdmx_rem_filt_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_rem_filt_req);
+ rsp_len = sizeof(struct sdmx_rem_filt_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_REMOVE_FILTER_CMD;
+ cmd->session_handle = session_handle;
+ cmd->filter_handle = filter_handle;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_remove_filter);
+
+/*
+ * Associates a key ladder index for the specified pid
+ *
+ * @session_handle: secure demux instance
+ * @pid: pid
+ * @key_ladder_index: key ladder index to associate to the pid
+ *
+ * Return error code
+ *
+ * Note: if pid already has some key ladder index associated, it will be
+ * overridden.
+ */
+int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_set_kl_ind_req *cmd;
+ struct sdmx_set_kl_ind_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_set_kl_ind_req);
+ rsp_len = sizeof(struct sdmx_set_kl_ind_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_SET_KL_IDX_CMD;
+ cmd->session_handle = session_handle;
+ cmd->pid = (u32)pid;
+ cmd->kl_index = key_ladder_index;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_set_kl_ind);
+
+/*
+ * Adds the specified pid to an existing raw (recording) filter
+ *
+ * @session_handle: secure demux instance
+ * @filter_handle: raw filter handle
+ * @pid: pid
+ *
+ * Return error code
+ */
+int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_add_raw_req *cmd;
+ struct sdmx_add_raw_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_add_raw_req);
+ rsp_len = sizeof(struct sdmx_add_raw_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_ADD_RAW_PID_CMD;
+ cmd->session_handle = session_handle;
+ cmd->filter_handle = filter_handle;
+ cmd->pid = (u32)pid;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_add_raw_pid);
+
+/*
+ * Removes the specified pid from a raw (recording) filter
+ *
+ * @session_handle: secure demux instance
+ * @filter_handle: raw filter handle
+ * @pid: pid
+ *
+ * Return error code
+ */
+int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_rem_raw_req *cmd;
+ struct sdmx_rem_raw_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_rem_raw_req);
+ rsp_len = sizeof(struct sdmx_rem_raw_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_REMOVE_RAW_PID_CMD;
+ cmd->session_handle = session_handle;
+ cmd->filter_handle = filter_handle;
+ cmd->pid = (u32)pid;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_remove_raw_pid);
+
+/*
+ * Call secure demux to perform processing on the specified input buffer
+ *
+ * @session_handle: secure demux instance
+ * @flags: input flags. Currently only EOS marking is supported.
+ * @input_buf_desc: input buffer descriptor
+ * @input_fill_count: number of bytes available in input buffer
+ * @input_read_offset: offset inside input buffer where data starts
+ * @error_indicators: returned general error indicators
+ * @status_indicators: returned general status indicators
+ * @num_filters: number of filters in filter status array
+ * @filter_status: filter status descriptor array
+ *
+ * Return error code
+ */
+int sdmx_process(int session_handle, u8 flags,
+ struct sdmx_buff_descr *input_buf_desc,
+ u32 *input_fill_count,
+ u32 *input_read_offset,
+ u32 *error_indicators,
+ u32 *status_indicators,
+ u32 num_filters,
+ struct sdmx_filter_status *filter_status)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_proc_req *cmd;
+ struct sdmx_proc_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+ (input_buf_desc == NULL) ||
+ (input_fill_count == NULL) || (input_read_offset == NULL) ||
+ (error_indicators == NULL) || (status_indicators == NULL) ||
+ (filter_status == NULL))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_proc_req)
+ + num_filters * sizeof(struct sdmx_filter_status);
+ rsp_len = sizeof(struct sdmx_proc_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_PROCESS_CMD;
+ cmd->session_handle = session_handle;
+ cmd->flags = flags;
+ cmd->in_buf_descr.base_addr = input_buf_desc->base_addr;
+ cmd->in_buf_descr.size = input_buf_desc->size;
+ cmd->inp_fill_cnt = *input_fill_count;
+ cmd->in_rd_offset = *input_read_offset;
+ cmd->num_filters = num_filters;
+ memcpy(cmd->filters_status, filter_status,
+ num_filters * sizeof(struct sdmx_filter_status));
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ /* Parse response struct */
+ *input_fill_count = rsp->inp_fill_cnt;
+ *input_read_offset = rsp->in_rd_offset;
+ *error_indicators = rsp->err_indicators;
+ *status_indicators = rsp->status_indicators;
+ memcpy(filter_status, cmd->filters_status,
+ num_filters * sizeof(struct sdmx_filter_status));
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_process);
+
+/*
+ * Returns session-level & filter-level debug counters
+ *
+ * @session_handle: secure demux instance
+ * @session_counters: returned session-level debug counters
+ * @num_filters: returned number of filters reported in filter_counters
+ * @filter_counters: returned filter-level debug counters array
+ *
+ * Return error code
+ */
+int sdmx_get_dbg_counters(int session_handle,
+ struct sdmx_session_dbg_counters *session_counters,
+ u32 *num_filters,
+ struct sdmx_filter_dbg_counters *filter_counters)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_get_counters_req *cmd;
+ struct sdmx_get_counters_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+ (session_counters == NULL) || (num_filters == NULL) ||
+ (filter_counters == NULL))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_get_counters_req);
+ rsp_len = sizeof(struct sdmx_get_counters_rsp)
+ + *num_filters * sizeof(struct sdmx_filter_dbg_counters);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_GET_DBG_COUNTERS_CMD;
+ cmd->session_handle = session_handle;
+ cmd->num_filters = *num_filters;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ /* Parse response struct */
+ *session_counters = rsp->session_counters;
+ *num_filters = rsp->num_filters;
+ memcpy(filter_counters, rsp->filter_counters,
+ *num_filters * sizeof(struct sdmx_filter_dbg_counters));
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_get_dbg_counters);
+
+/*
+ * Reset debug counters
+ *
+ * @session_handle: secure demux instance
+ *
+ * Return error code
+ */
+int sdmx_reset_dbg_counters(int session_handle)
+{
+ int res, cmd_len, rsp_len;
+ struct sdmx_rst_counters_req *cmd;
+ struct sdmx_rst_counters_rsp *rsp;
+ enum sdmx_status ret;
+
+ if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+ return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+ cmd_len = sizeof(struct sdmx_rst_counters_req);
+ rsp_len = sizeof(struct sdmx_rst_counters_rsp);
+
+ /* Lock shared memory */
+ mutex_lock(&sdmx_lock[session_handle]);
+
+ /* Get command and response buffers */
+ get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+ (void **)&rsp, &rsp_len);
+
+ /* Populate command struct */
+ cmd->cmd_id = SDMX_RESET_DBG_COUNTERS_CMD;
+ cmd->session_handle = session_handle;
+
+ /* Issue QSEECom command */
+ res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+ (void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+ if (res < 0) {
+ mutex_unlock(&sdmx_lock[session_handle]);
+ return SDMX_STATUS_GENERAL_FAILURE;
+ }
+
+ ret = rsp->ret;
+
+ mutex_unlock(&sdmx_lock[session_handle]);
+
+ return ret;
+}
+EXPORT_SYMBOL(sdmx_reset_dbg_counters);
diff --git a/drivers/media/dvb/mpq/demux/mpq_sdmx.h b/drivers/media/dvb/mpq/demux/mpq_sdmx.h
new file mode 100644
index 0000000..ffb9046
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_sdmx.h
@@ -0,0 +1,232 @@
+/* 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 _MPQ_SDMX_H
+#define _MPQ_SDMX_H
+
+#include <linux/types.h>
+
+/* Constant declarations */
+#define SDMX_MAX_SESSIONS (4)
+#define SDMX_LOOPBACK_PID (0x2000)
+
+/* Filter-level error indicators */
+#define SDMX_FILTER_SUCCESS (0)
+#define SDMX_FILTER_ERR_MD_BUF_FULL BIT(0)
+#define SDMX_FILTER_ERR_D_BUF_FULL BIT(1)
+#define SDMX_FILTER_ERR_D_LIN_BUFS_FULL BIT(2)
+#define SDMX_FILTER_ERR_INVALID_SCRAMBLE_BITS BIT(3)
+#define SDMX_FILTER_ERR_KL_IND_NOT_SET BIT(4)
+#define SDMX_FILTER_ERR_CAS_DECRYPT_ERROR BIT(5)
+#define SDMX_FILTER_ERR_SEC_VERIF_GENERAL_FAIL BIT(6)
+#define SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL BIT(7)
+#define SDMX_FILTER_ERR_SEC_INTERNAL_MALLOC_FAIL BIT(8)
+#define SDMX_FILTER_ERR_SEC_LEN_INVALID BIT(9)
+#define SDMX_FILTER_ERR_SEC_PUSI_PTR_INVALID BIT(10)
+#define SDMX_FILTER_ERR_TS_SYNC_BYTE_INVALID BIT(11)
+#define SDMX_FILTER_ERR_TS_TRANSPORT_ERR BIT(12)
+#define SDMX_FILTER_ERR_CONT_CNT_INVALID BIT(13)
+#define SDMX_FILTER_ERR_CONT_CNT_DUPLICATE BIT(14)
+#define SDMX_FILTER_ERR_INVALID_PES_HDR BIT(15)
+#define SDMX_FILTER_ERR_INVALID_PES_LEN BIT(16)
+#define SDMX_FILTER_ERR_INVALID_PES_ENCRYPTION BIT(17)
+#define SDMX_FILTER_ERR_SECURITY_FAULT BIT(18)
+#define SDMX_FILTER_ERR_IN_NS_BUFFER BIT(19)
+
+/* Filter-level status indicators */
+#define SDMX_FILTER_STATUS_EOS BIT(0)
+
+#define SDMX_INVALID_SESSION_HANDLE (-1)
+#define SDMX_INVALID_FILTER_HANDLE (-1)
+
+/* Input flags */
+#define SDMX_INPUT_FLAG_EOS BIT(0)
+
+
+enum sdmx_buf_mode {
+ SDMX_RING_BUF,
+ SDMX_LINEAR_GROUP_BUF,
+};
+
+enum sdmx_proc_mode {
+ SDMX_PUSH_MODE,
+ SDMX_PULL_MODE,
+};
+
+enum sdmx_inp_mode {
+ SDMX_PKT_ENC_MODE,
+ SDMX_BULK_ENC_MODE,
+ SDMX_CLEAR_MODE,
+};
+
+enum sdmx_pkt_format {
+ SDMX_188_BYTE_PKT = 188,
+ SDMX_192_BYTE_PKT = 192,
+ SDMX_195_BYTE_PKT = 195,
+};
+
+enum sdmx_status {
+ SDMX_SUCCESS = 0,
+ SDMX_STATUS_GENERAL_FAILURE = -1,
+ SDMX_STATUS_MAX_OPEN_SESSIONS_REACHED = -2,
+ SDMX_STATUS_INVALID_SESSION_HANDLE = -3,
+ SDMX_STATUS_INVALID_INPUT_PARAMS = -4,
+ SDMX_STATUS_UNSUPPORTED_MODE = -5,
+ SDMX_STATUS_INVALID_PID = -6,
+ SDMX_STATUS_OUT_OF_MEM = -7,
+ SDMX_STATUS_FILTER_EXISTS = -8,
+ SDMX_STATUS_INVALID_FILTER_HANDLE = -9,
+ SDMX_STATUS_MAX_RAW_PIDS_REACHED = -10,
+ SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11,
+ SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12,
+ SDMX_STATUS_INVALID_FILTER_CFG = -13,
+ SDMX_STATUS_ILLEGAL_WR_PTR_CHANGE = -14,
+ SDMX_STATUS_STALLED_IN_PULL_MODE = -15,
+ SDMX_STATUS_SECURITY_FAULT = -16,
+ SDMX_STATUS_NS_BUFFER_ERROR = -17,
+};
+
+enum sdmx_filter {
+ SDMX_PES_FILTER, /* Other PES */
+ SDMX_SEPARATED_PES_FILTER, /* Separated PES (for decoder) */
+ SDMX_SECTION_FILTER, /* Section */
+ SDMX_PCR_FILTER, /* PCR */
+ SDMX_RAW_FILTER, /* Recording */
+};
+
+struct sdmx_session_dbg_counters {
+ /* Total number of TS-packets input to SDMX. */
+ u32 ts_pkt_in;
+
+ /* Total number of TS-packets filtered out by SDMX. */
+ u32 ts_pkt_out;
+};
+
+struct sdmx_filter_dbg_counters {
+ int filter_handle;
+
+ /* Number of TS-packets filtered. */
+ u32 ts_pkt_count;
+
+ /* Number of TS-packets with adaptation field only (no payload). */
+ u32 ts_pkt_no_payload;
+
+ /* Number of TS-packets with the discontinuity indicator set. */
+ u32 ts_pkt_discont;
+
+ /* Number of duplicate TS-packets detected. */
+ u32 ts_pkt_dup;
+
+ /* Number of packets not decrypted because the key wasn't ready. */
+ u32 ts_pkt_key_not_ready;
+};
+
+struct sdmx_buff_descr {
+ /* Physical address where buffer starts */
+ void *base_addr;
+
+ /* Total size of buffer */
+ u32 size;
+};
+
+/*
+ * Data payload residing in the data buffers is described using this meta-data
+ * header. The meta data header specifies where the payload is located in the
+ * data buffer and how big it is.
+ * The meta data header optionally carries additional relevant meta data
+ * immediately following the meta-data header.
+ */
+struct sdmx_metadata_header {
+ /*
+ * Payload start offset inside data buffer. In case data is managed
+ * as a linear buffer group, this specifies buffer index.
+ */
+ u32 payload_start;
+
+ /* Payload length */
+ u32 payload_length;
+
+ /* Total metadata length (including this header, plus optional
+ * additional metadata.
+ */
+ u32 metadata_length;
+};
+
+
+struct sdmx_filter_status {
+ /* Secure demux filter handle */
+ int filter_handle;
+
+ /*
+ * Number of pending bytes in filter's output data buffer.
+ * For linear buffer mode, this is number of buffers pending.
+ */
+ u32 data_fill_count;
+
+ /*
+ * Offset in data buffer for next data payload to be written.
+ * For linear buffer mode, this is a buffer index.
+ */
+ u32 data_write_offset;
+
+ /* Number of pending bytes in filter's output meta data buffer */
+ u32 metadata_fill_count;
+
+ /* Offset in meta data buffer for next metadata header to be written */
+ u32 metadata_write_offset;
+
+ /* Errors (bitmap) reported by secure demux for this filter */
+ u32 error_indicators;
+
+ /* General status (bitmap) reported by secure demux for this filter */
+ u32 status_indicators;
+};
+
+int sdmx_open_session(int *session_handle);
+
+int sdmx_close_session(int session_handle);
+
+int sdmx_get_version(int session_handle, int32_t *version);
+
+int sdmx_set_session_cfg(int session_handle, enum sdmx_proc_mode proc_mode,
+ enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format,
+ u8 odd_scramble_bits, u8 even_scramble_bits);
+
+int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type,
+ struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode,
+ u32 num_data_bufs, struct sdmx_buff_descr *data_bufs,
+ int *filter_handle);
+
+int sdmx_remove_filter(int session_handle, int filter_handle);
+
+int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index);
+
+int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid);
+
+int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid);
+
+int sdmx_process(int session_handle, u8 flags,
+ struct sdmx_buff_descr *input_buf_desc,
+ u32 *input_fill_count, u32 *input_read_offset,
+ u32 *error_indicators,
+ u32 *status_indicators,
+ u32 num_filters,
+ struct sdmx_filter_status *filter_status);
+
+int sdmx_get_dbg_counters(int session_handle,
+ struct sdmx_session_dbg_counters *session_counters,
+ u32 *num_filters,
+ struct sdmx_filter_dbg_counters *filter_counters);
+
+int sdmx_reset_dbg_counters(int session_handle);
+
+#endif /* _MPQ_SDMX_H */
diff --git a/drivers/media/video/msm_vidc/hfi_packetization.c b/drivers/media/video/msm_vidc/hfi_packetization.c
index 4d3d07d..06e230d 100644
--- a/drivers/media/video/msm_vidc/hfi_packetization.c
+++ b/drivers/media/video/msm_vidc/hfi_packetization.c
@@ -1104,3 +1104,36 @@
}
return rc;
}
+
+static int get_hfi_ssr_type(enum hal_ssr_trigger_type type)
+{
+ int rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+ switch (type) {
+ case SSR_ERR_FATAL:
+ rc = HFI_TEST_SSR_SW_ERR_FATAL;
+ break;
+ case SSR_SW_DIV_BY_ZERO:
+ rc = HFI_TEST_SSR_SW_DIV_BY_ZERO;
+ break;
+ case SSR_HW_WDOG_IRQ:
+ rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+ break;
+ default:
+ dprintk(VIDC_WARN,
+ "SSR trigger type not recognized, using WDOG.\n");
+ }
+ return rc;
+}
+
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+ struct hfi_cmd_sys_test_ssr_packet *pkt)
+{
+ if (!pkt) {
+ dprintk(VIDC_ERR, "Invalid params, device: %p\n", pkt);
+ return -EINVAL;
+ }
+ pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet);
+ pkt->packet_type = HFI_CMD_SYS_TEST_SSR;
+ pkt->trigger_type = get_hfi_ssr_type(type);
+ return 0;
+}
diff --git a/drivers/media/video/msm_vidc/hfi_packetization.h b/drivers/media/video/msm_vidc/hfi_packetization.h
index a3edc7c..b2c6e08 100644
--- a/drivers/media/video/msm_vidc/hfi_packetization.h
+++ b/drivers/media/video/msm_vidc/hfi_packetization.h
@@ -79,5 +79,6 @@
struct hfi_cmd_session_set_property_packet *pkt,
u32 session_id, enum hal_property ptype, void *pdata);
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+ struct hfi_cmd_sys_test_ssr_packet *pkt);
#endif
-
diff --git a/drivers/media/video/msm_vidc/hfi_response_handler.c b/drivers/media/video/msm_vidc/hfi_response_handler.c
index 23829e5..cedd789 100644
--- a/drivers/media/video/msm_vidc/hfi_response_handler.c
+++ b/drivers/media/video/msm_vidc/hfi_response_handler.c
@@ -650,8 +650,8 @@
data_done.output_done.offset1 = pkt->offset;
data_done.output_done.frame_width = pkt->frame_width;
data_done.output_done.frame_height = pkt->frame_height;
- data_done.output_done.start_xCoord = pkt->start_x_coord;
- data_done.output_done.start_yCoord = pkt->start_y_coord;
+ data_done.output_done.start_x_coord = pkt->start_x_coord;
+ data_done.output_done.start_y_coord = pkt->start_y_coord;
data_done.output_done.input_tag1 = pkt->input_tag;
data_done.output_done.picture_type = pkt->picture_type;
data_done.output_done.packet_buffer1 = pkt->packet_buffer;
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 24407dd..b10787c 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -578,15 +578,18 @@
{
const struct msm_vidc_format *fmt = NULL;
struct hal_frame_size frame_sz;
+ struct hfi_device *hdev;
+ int stride, scanlines;
int extra_idx = 0;
int rc = 0;
int ret;
int i;
- if (!inst || !f) {
+ if (!inst || !f || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
+ hdev = inst->core->device;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
fmt = inst->fmts[CAPTURE_PORT];
else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
@@ -601,6 +604,8 @@
}
f->fmt.pix_mp.height = inst->prop.height;
f->fmt.pix_mp.width = inst->prop.width;
+ stride = inst->prop.width;
+ scanlines = inst->prop.height;
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
frame_sz.width = inst->prop.width;
frame_sz.height = inst->prop.height;
@@ -620,6 +625,16 @@
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
} else {
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ hdev->get_stride_scanline(COLOR_FMT_NV12,
+ inst->prop.width, inst->prop.height,
+ &stride, &scanlines);
+ break;
+ default:
+ dprintk(VIDC_WARN,
+ "Color format not recognized\n");
+ }
f->fmt.pix_mp.plane_fmt[0].sizeimage =
inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
extra_idx = EXTRADATA_IDX(fmt->num_planes);
@@ -631,7 +646,17 @@
inst->bufq[CAPTURE_PORT].
vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
-
+ }
+ if (stride && scanlines) {
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ (__u16)stride;
+ f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+ (__u16)scanlines;
+ } else {
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ (__u16)inst->prop.width;
+ f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+ (__u16)inst->prop.height;
}
} else {
dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 0326c79..05d3570 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -390,10 +390,16 @@
.name = "Slice Mode",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
- .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB,
.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.step = 1,
- .menu_skip_mask = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+ (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) |
+ (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) |
+ (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)
+ ),
+ .qmenu = NULL,
.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
@@ -421,6 +427,18 @@
.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB,
+ .name = "Slice GOB",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = MAX_SLICE_MB_SIZE,
+ .default_value = 1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
.name = "Intra Refresh Mode",
.type = V4L2_CTRL_TYPE_MENU,
@@ -1281,6 +1299,9 @@
case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
break;
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_GOB:
+ temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB;
+ break;
case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
default:
temp = 0;
@@ -1300,6 +1321,7 @@
}
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
property_id =
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index d4bb5a7..7e8732a 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -422,6 +422,9 @@
inst->buff_req.buffer[i].buffer_count_actual,
inst->buff_req.buffer[i].buffer_size);
}
+ dprintk(VIDC_PROF, "Input buffers: %d, Output buffers: %d\n",
+ inst->buff_req.buffer[0].buffer_count_actual,
+ inst->buff_req.buffer[1].buffer_count_actual);
signal_session_msg_receipt(cmd, inst);
}
@@ -716,6 +719,10 @@
(u32)fill_buf_done->packet_buffer1);
if (vb) {
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ vb->v4l2_planes[0].reserved[2] = fill_buf_done->start_x_coord;
+ vb->v4l2_planes[0].reserved[3] = fill_buf_done->start_y_coord;
+ vb->v4l2_planes[0].reserved[4] = fill_buf_done->frame_width;
+ vb->v4l2_planes[0].reserved[5] = fill_buf_done->frame_height;
if (!(fill_buf_done->flags1 &
HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
fill_buf_done->filled_len1) {
@@ -2208,3 +2215,18 @@
}
return ret;
};
+
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+ enum hal_ssr_trigger_type type)
+{
+ int rc = 0;
+ struct hfi_device *hdev;
+ if (!core && !core->device) {
+ dprintk(VIDC_WARN, "Invalid parameters: %p\n", core);
+ return -EINVAL;
+ }
+ hdev = core->device;
+ if (core->state == VIDC_CORE_INIT_DONE)
+ rc = hdev->core_trigger_ssr(hdev->hfi_device_data, type);
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index ff829d7..0a2075d 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -17,6 +17,7 @@
#define MAX_DBG_BUF_SIZE 4096
int msm_vidc_debug = 0x3;
int msm_fw_debug = 0x18;
+int msm_fw_debug_mode = 0x1;
struct debug_buffer {
char ptr[MAX_DBG_BUF_SIZE];
@@ -87,6 +88,33 @@
.read = core_info_read,
};
+static int trigger_ssr_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos) {
+ u32 ssr_trigger_val;
+ int rc;
+ struct msm_vidc_core *core = filp->private_data;
+ rc = sscanf(buf, "%d", &ssr_trigger_val);
+ if (rc < 0) {
+ dprintk(VIDC_WARN, "returning error err %d\n", rc);
+ rc = -EINVAL;
+ } else {
+ msm_vidc_trigger_ssr(core, ssr_trigger_val);
+ rc = count;
+ }
+ return rc;
+}
+
+static const struct file_operations ssr_fops = {
+ .open = trigger_ssr_open,
+ .write = trigger_ssr_write,
+};
+
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
struct dentry *parent)
{
@@ -117,6 +145,16 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ if (!debugfs_create_file("trigger_ssr", S_IWUSR,
+ dir, core, &ssr_fops)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_u32("fw_debug_mode", S_IRUGO | S_IWUSR,
+ parent, &msm_fw_debug_mode)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
failed_create_dir:
return dir;
}
@@ -165,6 +203,10 @@
completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
"pending" : "done");
}
+ write_str(&dbg_buf, "ETB Count: %d\n", inst->count.etb);
+ write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd);
+ write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb);
+ write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd);
return simple_read_from_buffer(buf, count, ppos,
dbg_buf.ptr, dbg_buf.filled_size);
}
@@ -213,8 +255,12 @@
break;
case MSM_VIDC_DEBUGFS_EVENT_EBD:
inst->count.ebd++;
- if (inst->count.ebd && inst->count.ebd == inst->count.etb)
+ if (inst->count.ebd && inst->count.ebd == inst->count.etb) {
toc(inst, FRAME_PROCESSING);
+ dprintk(VIDC_PROF, "EBD: FW needs input buffers\n");
+ }
+ if (inst->count.ftb == inst->count.fbd)
+ dprintk(VIDC_PROF, "EBD: FW needs output buffers\n");
break;
case MSM_VIDC_DEBUGFS_EVENT_FTB: {
inst->count.ftb++;
@@ -226,8 +272,12 @@
break;
case MSM_VIDC_DEBUGFS_EVENT_FBD:
inst->debug.samples++;
- if (inst->count.ebd && inst->count.fbd == inst->count.ftb)
+ if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
toc(inst, FRAME_PROCESSING);
+ dprintk(VIDC_PROF, "FBD: FW needs output buffers\n");
+ }
+ if (inst->count.etb == inst->count.ebd)
+ dprintk(VIDC_PROF, "FBD: FW needs input buffers\n");
break;
default:
dprintk(VIDC_ERR, "Invalid state in debugfs: %d\n", e);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
index b3bb6e1..07568ef 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -43,6 +43,7 @@
extern int msm_vidc_debug;
extern int msm_fw_debug;
+extern int msm_fw_debug_mode;
#define dprintk(__level, __fmt, arg...) \
do { \
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 52c1de8..16bf753 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -237,4 +237,6 @@
};
void handle_cmd_response(enum command_response cmd, void *data);
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+ enum hal_ssr_trigger_type type);
#endif
diff --git a/drivers/media/video/msm_vidc/venus_hfi.c b/drivers/media/video/msm_vidc/venus_hfi.c
index 1ccd583..5168b7a 100644
--- a/drivers/media/video/msm_vidc/venus_hfi.c
+++ b/drivers/media/video/msm_vidc/venus_hfi.c
@@ -37,6 +37,17 @@
#define SHARED_QSIZE 0x1000000
+static const u32 venus_qdss_entries[][2] = {
+ {0xFC307000, 0x1000},
+ {0xFC322000, 0x1000},
+ {0xFC319000, 0x1000},
+ {0xFC31A000, 0x1000},
+ {0xFC31B000, 0x1000},
+ {0xFC321000, 0x1000},
+ {0xFA180000, 0x1000},
+ {0xFA181000, 0x1000},
+};
+
static struct msm_bus_vectors enc_ocmem_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
@@ -926,8 +937,28 @@
static void venus_hfi_interface_queues_release(struct venus_hfi_device *device)
{
int i;
+ struct hfi_mem_map_table *qdss;
+ struct hfi_mem_map *mem_map;
+ int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
- venus_hfi_free(device->hal_client, device->mem_addr.mem_data);
+ if (device->qdss.mem_data) {
+ qdss = (struct hfi_mem_map_table *)
+ device->qdss.align_virtual_addr;
+ qdss->mem_map_num_entries = num_entries;
+ qdss->mem_map_table_base_addr =
+ (u32 *)((u32)device->qdss.align_device_addr +
+ sizeof(struct hfi_mem_map_table));
+ mem_map = (struct hfi_mem_map *)(qdss + 1);
+ for (i = 0; i < num_entries; i++) {
+ msm_iommu_unmap_contig_buffer(
+ (unsigned long)(mem_map[i].virtual_addr),
+ device->resources.io_map[NS_MAP].domain,
+ 1, SZ_4K);
+ }
+ venus_hfi_free(device->hal_client, device->qdss.mem_data);
+ }
+ venus_hfi_free(device->hal_client, device->iface_q_table.mem_data);
+ venus_hfi_free(device->hal_client, device->sfr.mem_data);
for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
device->iface_queues[i].q_hdr = NULL;
@@ -950,6 +981,41 @@
msm_smem_delete_client(device->hal_client);
device->hal_client = NULL;
}
+static int venus_hfi_get_qdss_iommu_virtual_addr(struct hfi_mem_map *mem_map,
+ int domain)
+{
+ int i;
+ int rc = 0;
+ unsigned long iova = 0;
+ int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
+
+ for (i = 0; i < num_entries; i++) {
+ rc = msm_iommu_map_contig_buffer(venus_qdss_entries[i][0],
+ domain, 1 , venus_qdss_entries[i][1],
+ SZ_4K, 0, &iova);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "IOMMU QDSS mapping failed for addr 0x%x",
+ venus_qdss_entries[i][0]);
+ rc = -ENOMEM;
+ break;
+ }
+ mem_map[i].virtual_addr = (u32) iova;
+ mem_map[i].physical_addr = venus_qdss_entries[i][0];
+ mem_map[i].size = venus_qdss_entries[i][1];
+ mem_map[i].attr = 0x0;
+ }
+ if (i < num_entries) {
+ dprintk(VIDC_ERR,
+ "IOMMU QDSS mapping failed, Freeing entries %d", i);
+ for (--i; i >= 0; i--) {
+ msm_iommu_unmap_contig_buffer(
+ (unsigned long)(mem_map[i].virtual_addr),
+ domain, 1, SZ_4K);
+ }
+ }
+ return rc;
+}
static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev,
int domain)
@@ -958,24 +1024,25 @@
struct hfi_queue_header *q_hdr;
u8 i;
int rc = 0;
+ struct hfi_mem_map_table *qdss;
+ struct hfi_mem_map *mem_map;
struct vidc_iface_q_info *iface_q;
struct hfi_sfr_struct *vsfr;
struct vidc_mem_addr *mem_addr;
int offset = 0;
- int size_1m = 1024 * 1024;
- int uc_size = (UC_SIZE + size_1m - 1) & (~(size_1m - 1));
+ int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
mem_addr = &dev->mem_addr;
rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, uc_size, 1,
+ dev->hal_client, QUEUE_SIZE, 1,
0, domain);
if (rc) {
dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
- return -ENOMEM;
+ goto fail_alloc_queue;
}
dev->iface_q_table.align_virtual_addr = mem_addr->align_virtual_addr;
dev->iface_q_table.align_device_addr = mem_addr->align_device_addr;
dev->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE;
- dev->iface_q_table.mem_data = NULL;
+ dev->iface_q_table.mem_data = mem_addr->mem_data;
offset += dev->iface_q_table.mem_size;
for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
@@ -992,18 +1059,31 @@
venus_hfi_set_queue_hdr_defaults(iface_q->q_hdr);
}
- dev->qdss.align_device_addr = mem_addr->align_device_addr + offset;
- dev->qdss.align_virtual_addr = mem_addr->align_virtual_addr + offset;
- dev->qdss.mem_size = QDSS_SIZE;
- dev->qdss.mem_data = NULL;
- offset += dev->qdss.mem_size;
-
- dev->sfr.align_device_addr = mem_addr->align_device_addr + offset;
- dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr + offset;
- dev->sfr.mem_size = SFR_SIZE;
- dev->sfr.mem_data = NULL;
- offset += dev->sfr.mem_size;
-
+ rc = venus_hfi_alloc((void *) mem_addr,
+ dev->hal_client, QDSS_SIZE, 1,
+ 0, domain);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "qdss_alloc_fail: QDSS messages logging will not work");
+ dev->qdss.align_device_addr = NULL;
+ } else {
+ dev->qdss.align_device_addr = mem_addr->align_device_addr;
+ dev->qdss.align_virtual_addr = mem_addr->align_virtual_addr;
+ dev->qdss.mem_size = QDSS_SIZE;
+ dev->qdss.mem_data = mem_addr->mem_data;
+ }
+ rc = venus_hfi_alloc((void *) mem_addr,
+ dev->hal_client, SFR_SIZE, 1,
+ 0, domain);
+ if (rc) {
+ dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work");
+ dev->sfr.align_device_addr = NULL;
+ } else {
+ dev->sfr.align_device_addr = mem_addr->align_device_addr;
+ dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr;
+ dev->sfr.mem_size = SFR_SIZE;
+ dev->sfr.mem_data = mem_addr->mem_data;
+ }
q_tbl_hdr = (struct hfi_queue_table_header *)
dev->iface_q_table.align_virtual_addr;
q_tbl_hdr->qtbl_version = 0;
@@ -1035,9 +1115,9 @@
venus_hfi_write_register(dev->hal_data->register_base_addr,
VIDC_UC_REGION_ADDR,
- (u32) mem_addr->align_device_addr, 0);
+ (u32) dev->iface_q_table.align_device_addr, 0);
venus_hfi_write_register(dev->hal_data->register_base_addr,
- VIDC_UC_REGION_SIZE, mem_addr->mem_size, 0);
+ VIDC_UC_REGION_SIZE, SHARED_QSIZE, 0);
venus_hfi_write_register(dev->hal_data->register_base_addr,
VIDC_CPU_CS_SCIACMDARG2,
(u32) dev->iface_q_table.align_device_addr,
@@ -1045,16 +1125,33 @@
venus_hfi_write_register(dev->hal_data->register_base_addr,
VIDC_CPU_CS_SCIACMDARG1, 0x01,
dev->iface_q_table.align_virtual_addr);
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+
+ qdss = (struct hfi_mem_map_table *) dev->qdss.align_virtual_addr;
+ qdss->mem_map_num_entries = num_entries;
+ qdss->mem_map_table_base_addr =
+ (u32 *) ((u32)dev->qdss.align_device_addr +
+ sizeof(struct hfi_mem_map_table));
+ mem_map = (struct hfi_mem_map *)(qdss + 1);
+ rc = venus_hfi_get_qdss_iommu_virtual_addr(mem_map, domain);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "IOMMU mapping failed, Freeing qdss memdata");
+ venus_hfi_free(dev->hal_client, dev->qdss.mem_data);
+ dev->qdss.mem_data = NULL;
+ }
+ if (!IS_ERR_OR_NULL(dev->qdss.align_device_addr))
+ venus_hfi_write_register(dev->hal_data->register_base_addr,
VIDC_MMAP_ADDR,
(u32) dev->qdss.align_device_addr, 0);
vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
vsfr->bufSize = SFR_SIZE;
-
- venus_hfi_write_register(dev->hal_data->register_base_addr,
+ if (!IS_ERR_OR_NULL(dev->sfr.align_device_addr))
+ venus_hfi_write_register(dev->hal_data->register_base_addr,
VIDC_SFR_ADDR, (u32)dev->sfr.align_device_addr , 0);
return 0;
+fail_alloc_queue:
+ return -ENOMEM;
}
static int venus_hfi_core_start_cpu(struct venus_hfi_device *device)
@@ -1139,6 +1236,8 @@
hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
hfi->debug_config = debug;
hfi->debug_mode = HFI_DEBUG_MODE_QUEUE;
+ if (msm_fw_debug_mode <= HFI_DEBUG_MODE_QDSS)
+ hfi->debug_mode = msm_fw_debug_mode;
if (venus_hfi_iface_cmdq_write(device, pkt))
return -ENOTEMPTY;
return 0;
@@ -1371,6 +1470,33 @@
return rc;
}
+static int venus_hfi_core_trigger_ssr(void *device,
+ enum hal_ssr_trigger_type type)
+{
+ struct hfi_cmd_sys_test_ssr_packet pkt;
+ int rc = 0;
+ struct venus_hfi_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ dprintk(VIDC_ERR, "invalid device");
+ return -ENODEV;
+ }
+
+ rc = create_pkt_ssr_cmd(type, &pkt);
+ if (rc) {
+ dprintk(VIDC_ERR, "core_ping: failed to create packet");
+ goto err_create_pkt;
+ }
+
+ if (venus_hfi_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+
+err_create_pkt:
+ return rc;
+}
+
static int venus_hfi_session_set_property(void *sess,
enum hal_property ptype, void *pdata)
{
@@ -2192,7 +2318,7 @@
break;
ret = table[i].freq;
}
- dprintk(VIDC_DBG, "Required clock rate = %lu\n", ret);
+ dprintk(VIDC_PROF, "Required clock rate = %lu\n", ret);
return ret;
}
@@ -2870,6 +2996,13 @@
return rc;
}
+int venus_hfi_get_stride_scanline(int color_fmt,
+ int width, int height, int *stride, int *scanlines) {
+ *stride = VENUS_Y_STRIDE(color_fmt, width);
+ *scanlines = VENUS_Y_SCANLINES(color_fmt, height);
+ return 0;
+}
+
static void *venus_hfi_add_device(u32 device_id, struct platform_device *pdev,
void (*callback) (enum command_response cmd, void *data))
{
@@ -2977,6 +3110,7 @@
hdev->core_release = venus_hfi_core_release;
hdev->core_pc_prep = venus_hfi_core_pc_prep;
hdev->core_ping = venus_hfi_core_ping;
+ hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr;
hdev->session_init = venus_hfi_session_init;
hdev->session_end = venus_hfi_session_end;
hdev->session_abort = venus_hfi_session_abort;
@@ -3007,6 +3141,7 @@
hdev->load_fw = venus_hfi_load_fw;
hdev->unload_fw = venus_hfi_unload_fw;
hdev->get_fw_info = venus_hfi_get_fw_info;
+ hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
}
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/video/msm_vidc/venus_hfi.h b/drivers/media/video/msm_vidc/venus_hfi.h
index f825c20..8770ace 100644
--- a/drivers/media/video/msm_vidc/venus_hfi.h
+++ b/drivers/media/video/msm_vidc/venus_hfi.h
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <mach/ocmem.h>
+#include <mach/iommu_domains.h>
#include "vidc_hfi_api.h"
#include "msm_smem.h"
@@ -79,6 +80,18 @@
u32 qhdr_write_idx;
};
+struct hfi_mem_map_table {
+ u32 mem_map_num_entries;
+ u32 *mem_map_table_base_addr;
+};
+
+struct hfi_mem_map {
+ u32 virtual_addr;
+ u32 physical_addr;
+ u32 size;
+ u32 attr;
+};
+
#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+ sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
@@ -92,8 +105,8 @@
#define QDSS_SIZE 4096
#define SFR_SIZE 4096
-#define UC_SIZE (VIDC_IFACEQ_TABLE_SIZE + \
- (VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ) + QDSS_SIZE + SFR_SIZE)
+#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \
+ (VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ))
enum vidc_hw_reg {
VIDC_HWREG_CTRL_STATUS = 0x1,
diff --git a/drivers/media/video/msm_vidc/vidc_hfi.h b/drivers/media/video/msm_vidc/vidc_hfi.h
index 6ff0921..c82f665 100644
--- a/drivers/media/video/msm_vidc/vidc_hfi.h
+++ b/drivers/media/video/msm_vidc/vidc_hfi.h
@@ -13,6 +13,7 @@
#ifndef __H_VIDC_HFI_H__
#define __H_VIDC_HFI_H__
+#include <media/msm_media_info.h>
#include "vidc_hfi_helper.h"
#include "vidc_hfi_api.h"
diff --git a/drivers/media/video/msm_vidc/vidc_hfi_api.h b/drivers/media/video/msm_vidc/vidc_hfi_api.h
index 370785c..5428267 100644
--- a/drivers/media/video/msm_vidc/vidc_hfi_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hfi_api.h
@@ -407,6 +407,12 @@
HAL_UNUSED_COLOR = 0x10000000,
};
+enum hal_ssr_trigger_type {
+ SSR_ERR_FATAL = 1,
+ SSR_SW_DIV_BY_ZERO,
+ SSR_HW_WDOG_IRQ,
+};
+
struct hal_uncompressed_format_select {
enum hal_buffer buffer_type;
enum hal_uncompressed_format format;
@@ -924,8 +930,8 @@
u32 offset1;
u32 frame_width;
u32 frame_height;
- u32 start_xCoord;
- u32 start_yCoord;
+ u32 start_x_coord;
+ u32 start_y_coord;
u32 input_tag;
u32 input_tag1;
enum hal_picture picture_type;
@@ -1009,6 +1015,7 @@
int (*core_release)(void *device);
int (*core_pc_prep)(void *device);
int (*core_ping)(void *device);
+ int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type);
void *(*session_init)(void *device, u32 session_id,
enum hal_domain session_type, enum hal_video_codec codec_type);
int (*session_end)(void *session);
@@ -1050,6 +1057,8 @@
int (*load_fw)(void *dev);
void (*unload_fw)(void *dev);
int (*get_fw_info)(void *dev, enum fw_info info);
+ int (*get_stride_scanline)(int color_fmt, int width,
+ int height, int *stride, int *scanlines);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/media/video/msm_vidc/vidc_hfi_helper.h b/drivers/media/video/msm_vidc/vidc_hfi_helper.h
index 7531811..37c051e 100644
--- a/drivers/media/video/msm_vidc/vidc_hfi_helper.h
+++ b/drivers/media/video/msm_vidc/vidc_hfi_helper.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
@@ -685,6 +685,11 @@
#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE \
(HFI_MSG_SESSION_COMMON_START + 0x2)
+#define HFI_CMD_SYS_TEST_SSR (HFI_CMD_SYS_TEST_START + 0x1)
+#define HFI_TEST_SSR_SW_ERR_FATAL 0x1
+#define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2
+#define HFI_TEST_SSR_HW_WDOG_IRQ 0x3
+
struct vidc_hal_msg_pkt_hdr {
u32 size;
u32 packet;
@@ -871,4 +876,10 @@
u8 rg_data[1];
};
+struct hfi_cmd_sys_test_ssr_packet {
+ u32 size;
+ u32 packet_type;
+ u32 trigger_type;
+};
+
#endif
diff --git a/drivers/media/video/msmb/isp/msm_buf_mgr.h b/drivers/media/video/msmb/isp/msm_buf_mgr.h
index a44b5ec..b96d9fe 100644
--- a/drivers/media/video/msmb/isp/msm_buf_mgr.h
+++ b/drivers/media/video/msmb/isp/msm_buf_mgr.h
@@ -17,9 +17,8 @@
#include <mach/iommu_domains.h>
#include "msm_sd.h"
-#define BUF_SRC_SHIFT 16
/*Buffer source can be from userspace / HAL*/
-#define BUF_SRC(id) (id >> BUF_SRC_SHIFT)
+#define BUF_SRC(id) (id & ISP_NATIVE_BUF_BIT)
struct msm_isp_buf_mgr;
diff --git a/drivers/media/video/msmb/isp/msm_isp.h b/drivers/media/video/msmb/isp/msm_isp.h
index c320a1a..1c82f45 100644
--- a/drivers/media/video/msmb/isp/msm_isp.h
+++ b/drivers/media/video/msmb/isp/msm_isp.h
@@ -132,6 +132,10 @@
int (*get_platform_data) (struct vfe_device *vfe_dev);
};
struct msm_vfe_stats_ops {
+ void (*cfg_framedrop) (struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_stream *stream_info);
+ void (*clear_framedrop) (struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_stream *stream_info);
void (*cfg_comp_mask) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_comp_mask) (struct vfe_device *vfe_dev,
@@ -142,7 +146,7 @@
struct msm_vfe_stats_stream *stream_info);
void (*cfg_wm_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_stats_stream *stream_info);
void (*clear_wm_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
@@ -158,6 +162,10 @@
uint32_t (*get_frame_id) (struct vfe_device *vfe_dev);
uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1);
+ uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev);
+ uint32_t (*get_active_pingpong_idx) (uint32_t pingpong_status,
+ enum msm_isp_stats_type stats_type);
+
};
struct msm_vfe_ops {
@@ -180,6 +188,7 @@
uint8_t num_rdi_master;
uint8_t num_comp_mask;
uint32_t min_wm_ub;
+ uint8_t num_stats_comp_mask;
};
enum msm_vfe_axi_state {
@@ -241,23 +250,33 @@
enum msm_vfe_inputmux input_mux;
};
-
+enum msm_vfe_stats_state {
+ STATE_AVALIABLE,
+ STATE_INACTIVE,
+ STATE_ACTIVE,
+ STATE_START_PENDING,
+ STATE_STOP_PENDING,
+ STATE_STOPPING,
+};
struct msm_vfe_stats_stream {
uint32_t frame_id;
uint8_t enable;
enum msm_isp_stats_type stats_type;
- uint8_t comp_mask_index;
+ int8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
uint32_t stream_id;
uint32_t bufq_handle;
uint32_t stream_handle;
uint32_t framedrop_pattern;
+ uint8_t comp_flag;
+ uint8_t comp_idx;
+ enum msm_vfe_stats_state state;
};
struct msm_vfe_stats_composite_info {
- uint32_t stream_handle;
- uint32_t stream_composite_mask;
+ uint32_t stats_mask;
+ uint8_t comp_flag;
};
enum msm_wm_ub_cfg_type {
@@ -288,7 +307,7 @@
struct msm_vfe_stats_shared_data {
struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX];
struct msm_vfe_stats_composite_info
- comp_info[MAX_NUM_STATS_COMP_MASK];
+ composite_info[MAX_NUM_STATS_COMP_MASK];
uint8_t num_active_stream;
uint8_t num_used_composite_mask;
uint16_t stream_handle_cnt;
diff --git a/drivers/media/video/msmb/isp/msm_isp40.c b/drivers/media/video/msmb/isp/msm_isp40.c
index b9788eb..6c90763 100644
--- a/drivers/media/video/msmb/isp/msm_isp40.c
+++ b/drivers/media/video/msmb/isp/msm_isp40.c
@@ -862,7 +862,7 @@
static void msm_vfe40_cfg_axi_ub(struct vfe_device *vfe_dev)
{
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-
+ axi_data->wm_ub_cfg_policy = MSM_WM_UB_EQUAL_SLICING;
if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev);
else
@@ -937,7 +937,7 @@
static void msm_vfe40_stats_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_stats_stream *stream_info)
{
}
@@ -984,6 +984,56 @@
{
return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
}
+
+static uint32_t msm_vfe40_stats_get_active_pingpong_idx(
+ uint32_t pingpong_status,
+ enum msm_isp_stats_type stats_type)
+{
+ int pingpong_bit = 0;
+ switch (stats_type) {
+ case MSM_ISP_STATS_AWB:
+ if (pingpong_status & (1 << 11))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_RS:
+ if (pingpong_status & (1 << 12))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_CS:
+ if (pingpong_status & (1 << 13))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_IHIST:
+ if (pingpong_status & (1 << 14))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_BG:
+ if (pingpong_status & (1 << 9))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_BF:
+ if (pingpong_status & (1 << 10))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_BE:
+ if (pingpong_status & (1 << 8))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_BHIST:
+ if (pingpong_status & (1 << 15))
+ pingpong_bit = 1; /* pong is active */
+ break;
+ case MSM_ISP_STATS_SKIN:
+ case MSM_ISP_STATS_AEC:
+ case MSM_ISP_STATS_AF:
+ default:
+ pr_err("%s: not supported stats type = %d\n",
+ __func__, stats_type);
+ return -EINVAL;
+ }
+ return pingpong_bit;
+}
+
static int msm_vfe40_get_platform_data(struct vfe_device *vfe_dev)
{
int rc = 0;
@@ -1041,6 +1091,7 @@
.num_rdi = 3,
.num_rdi_master = 3,
.min_wm_ub = 64,
+ .num_stats_comp_mask = 2,
};
static struct v4l2_subdev_core_ops msm_vfe40_subdev_core_ops = {
@@ -1118,6 +1169,9 @@
.get_comp_mask = msm_vfe40_stats_get_comp_mask,
.get_wm_mask = msm_vfe40_stats_get_wm_mask,
.get_frame_id = msm_vfe40_stats_get_frame_id,
+ .get_pingpong_status = msm_vfe40_get_pingpong_status,
+ .get_active_pingpong_idx =
+ msm_vfe40_stats_get_active_pingpong_idx,
},
},
.axi_hw_info = &msm_vfe40_axi_hw_info,
diff --git a/drivers/media/video/msmb/isp/msm_isp_axi_util.c b/drivers/media/video/msmb/isp/msm_isp_axi_util.c
index fe55b40..7e62071 100644
--- a/drivers/media/video/msmb/isp/msm_isp_axi_util.c
+++ b/drivers/media/video/msmb/isp/msm_isp_axi_util.c
@@ -637,7 +637,6 @@
complete(&vfe_dev->stream_config_complete);
}
}
-
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
@@ -687,7 +686,7 @@
vfe_dev, stream_info->wm[i],
pingpong_status, buf->mapped_info[i].paddr);
- if (stream_info->buf[pingpong_bit]) {
+ if (stream_info->buf[pingpong_bit] && tv) {
if (stream_info->buf_divert) {
buf_event.frame_id = stream_info->frame_id;
buf_event.timestamp = *tv;
diff --git a/drivers/media/video/msmb/isp/msm_isp_stats_util.c b/drivers/media/video/msmb/isp/msm_isp_stats_util.c
index 15f4c23..86a4a3d 100644
--- a/drivers/media/video/msmb/isp/msm_isp_stats_util.c
+++ b/drivers/media/video/msmb/isp/msm_isp_stats_util.c
@@ -13,6 +13,41 @@
#include <media/v4l2-subdev.h>
#include "msm_isp_util.h"
#include "msm_isp_stats_util.h"
+#define VFE_PING_ACTIVE_FLAG 0xFFFFFFFF
+#define VFE_PONG_ACTIVE_FLAG 0x0
+
+int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
+ struct msm_isp_buffer *out_buf)
+{
+ int rc = -1;
+ struct msm_isp_buffer *buf;
+ int active_bit = 0;
+ int buf_idx;
+ uint32_t bufq_handle = stream_info->bufq_handle;
+
+ out_buf = NULL;
+ active_bit = vfe_dev->hw_info->vfe_ops.stats_ops.
+ get_active_pingpong_idx(pingpong_status,
+ stream_info->stats_type);
+ buf_idx = active_bit^0x1;
+
+ rc = vfe_dev->buf_mgr->ops->get_buf(
+ vfe_dev->buf_mgr, bufq_handle, &buf);
+ if (rc < 0) {
+ pr_err("%s: No free buffer, stats_type = %d\n",
+ __func__, stream_info->stats_type);
+ return rc;
+ }
+ vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
+ vfe_dev, stream_info->stats_type,
+ pingpong_status, buf->mapped_info[buf_idx].paddr);
+
+ if (stream_info->buf[buf_idx])
+ out_buf = stream_info->buf[buf_idx];
+ stream_info->buf[buf_idx] = buf;
+ return 0;
+}
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
@@ -22,7 +57,7 @@
uint32_t stats_comp_mask = 0, stats_mask = 0;
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
- get_comp_mask(irq_status0, irq_status1);
+ get_comp_mask(irq_status0, irq_status1);
stats_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_wm_mask(irq_status0, irq_status1);
if (!(stats_comp_mask || stats_mask))
@@ -31,10 +66,100 @@
/* TD: process comp/non comp stats */
}
+static int msm_isp_stats_reserve_comp_mask(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_shared_data *stats_data,
+ struct msm_vfe_stats_stream *stream_info)
+{
+ int i;
+ uint8_t num_stats_comp;
+ int8_t comp_idx = -1;
+ if (stream_info->comp_flag == 0)
+ return 0;
+
+ num_stats_comp = vfe_dev->axi_data.hw_info->num_stats_comp_mask;
+ for (i = 0; i < num_stats_comp; i++) {
+ if (!stats_data->composite_info[i].stats_mask == 0 &&
+ comp_idx < 0)
+ comp_idx = i;
+ if (stats_data->composite_info[i].comp_flag ==
+ stream_info->comp_flag) {
+ comp_idx = i;
+ break;
+ }
+ }
+ if (comp_idx < 0) {
+ pr_err("%s: no more stats comp idx\n", __func__);
+ return -EACCES;
+ }
+ stats_data->composite_info[comp_idx].stats_mask |=
+ (1 << stream_info->stats_type);
+ if (stats_data->composite_info[comp_idx].comp_flag == 0)
+ stats_data->composite_info[comp_idx].comp_flag =
+ stream_info->comp_flag;
+ stream_info->comp_idx = comp_idx;
+ return 0;
+}
+
+static int msm_isp_stats_unreserve_comp_mask(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_shared_data *stats_data,
+ struct msm_vfe_stats_stream *stream_info)
+{
+ uint8_t comp_idx = stream_info->comp_idx;
+
+ if (stream_info->comp_flag == 0)
+ return 0;
+ stats_data->composite_info[comp_idx].stats_mask &=
+ ~(1 << stream_info->stats_type);
+ if (stats_data->composite_info[comp_idx].stats_mask == 0)
+ memset(&stats_data->composite_info[comp_idx], 0,
+ sizeof(struct msm_vfe_stats_composite_info));
+ return 0;
+}
+
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0;
- /*To Do*/
+ struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd = arg;
+ struct msm_vfe_stats_stream *stream_info = NULL;
+ struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+
+ if (stream_cfg_cmd->stats_type < MSM_ISP_STATS_AEC ||
+ stream_cfg_cmd->stats_type >= MSM_ISP_STATS_MAX) {
+ pr_err("%s: invalid stats type %d received\n",
+ __func__, stream_cfg_cmd->stats_type);
+ return -EINVAL;
+ }
+ stream_info = &stats_data->stream_info[stream_cfg_cmd->stats_type];
+ if (stream_info->stream_handle != 0) {
+ pr_err("%s: stats type %d has been used already\n",
+ __func__, stream_cfg_cmd->stats_type);
+ return -EBUSY;
+ }
+
+ stats_data->stream_handle_cnt++;
+ if (stats_data->stream_handle_cnt == 0)
+ stats_data->stream_handle_cnt++;
+ stream_info->stream_handle =
+ stats_data->stream_handle_cnt << 16 |
+ stream_cfg_cmd->stats_type;
+ stream_info->enable = 0;
+ stream_info->stats_type = stream_cfg_cmd->stats_type;
+ stream_info->comp_flag = stream_cfg_cmd->comp_flag;
+ stream_info->session_id = stream_cfg_cmd->session_id;
+ stream_info->stream_id = stream_cfg_cmd->stream_id;
+ stream_info->framedrop_pattern = stream_cfg_cmd->framedrop_pattern;
+ stream_cfg_cmd->stream_handle = stream_info->stream_handle;
+ msm_isp_stats_reserve_comp_mask(vfe_dev, stats_data, stream_info);
+ if (stream_info->comp_flag)
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ cfg_comp_mask(vfe_dev, stream_info);
+ else
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ cfg_wm_irq_mask(vfe_dev, stream_info);
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ cfg_wm_reg(vfe_dev, stream_info);
return rc;
}
@@ -45,25 +170,94 @@
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_vfe_stats_stream *stream_info =
&stats_data->stream_info[
- (stream_release_cmd->stream_handle & 0xFF)];
+ (stream_release_cmd->stream_handle & 0xFF)];
- if (stream_info == NULL)
- rc = -1;
+ if (stream_info == NULL ||
+ stream_info->stream_handle !=
+ stream_release_cmd->stream_handle) {
+ pr_err("%s: handle mismatch(0x%x, 0x%x\n",
+ __func__, stream_info->stream_handle,
+ stream_release_cmd->stream_handle);
+ rc = -EINVAL;
+ }
+ if (stream_info->enable) {
+ struct msm_vfe_stats_stream_cfg_cmd stop_cmd;
+ memset(&stop_cmd, 0, sizeof(stop_cmd));
+ stop_cmd.num_streams = 1;
+ stop_cmd.stream_handle[0] = stream_release_cmd->stream_handle;
+ stop_cmd.enable = 0;
+ rc = msm_isp_cfg_stats_stream(vfe_dev, (void *)&stop_cmd);
+ if (rc < 0) {
+ pr_err("%s: cannot stop stats type %d\n",
+ __func__, stream_info->stats_type);
+ return -EPERM;
+ }
+ }
+ if (stream_info->bufq_handle) {
+ vfe_dev->buf_mgr->ops->release_buf(vfe_dev->buf_mgr,
+ stream_info->bufq_handle);
+ stream_info->bufq_handle = 0;
+ }
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ clear_wm_reg(vfe_dev, stream_info);
+ if (stream_info->comp_flag) {
+ msm_isp_stats_unreserve_comp_mask(vfe_dev,
+ stats_data, stream_info);
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ clear_comp_mask(vfe_dev, stream_info);
+ } else {
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ clear_wm_irq_mask(vfe_dev, stream_info);
+ }
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ clear_framedrop(vfe_dev, stream_info);
+ memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream));
return rc;
}
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0;
- uint32_t stats_mask = 0;
- uint8_t enable = 0;
+ int i, rc = 0;
uint32_t pingpong_status = 0;
struct msm_isp_buffer *buf = NULL;
- enum msm_isp_stats_type stats_type = MSM_ISP_STATS_BE;
+ struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
+ struct msm_vfe_stats_stream *stream_info;
+ struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
+ int idx;
+ uint32_t stats_mask = 0;
+ uint8_t enable = stream_cfg_cmd->enable;
+
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ idx = stream_cfg_cmd->stream_handle[i] & 0xF;
+ stream_info = &stats_data->stream_info[idx];
+ if (stream_info->stream_handle !=
+ stream_cfg_cmd->stream_handle[i]) {
+ pr_err("%s: invalid stream handle -0x%x received\n",
+ __func__, stream_cfg_cmd->stream_handle[i]);
+ continue;
+ }
+ if (enable) {
+ stream_info->bufq_handle =
+ vfe_dev->buf_mgr->ops->get_bufq_handle(
+ vfe_dev->buf_mgr, stream_info->session_id,
+ stream_info->stream_id);
+ if (stream_info->bufq_handle == 0) {
+ pr_err("%s: no buf configured for stats type = %d\n",
+ __func__,
+ stream_info->stats_type);
+ return -EINVAL;
+ }
+ }
+ /* config ping address */
+ pingpong_status = VFE_PONG_ACTIVE_FLAG;
+ stats_mask |= (1 << stream_info->stats_type);
+ msm_isp_stats_cfg_ping_pong_address(vfe_dev,
+ stream_info, pingpong_status, buf);
+ pingpong_status = VFE_PING_ACTIVE_FLAG;
+ msm_isp_stats_cfg_ping_pong_address(vfe_dev,
+ stream_info, pingpong_status, buf);
+ }
vfe_dev->hw_info->vfe_ops.stats_ops.
- stats_enable(vfe_dev, stats_mask, enable);
- vfe_dev->hw_info->vfe_ops.stats_ops.
- update_ping_pong_addr(vfe_dev, stats_type,
- pingpong_status, buf->mapped_info[0].paddr);
+ stats_enable(vfe_dev, stats_mask, enable);
return rc;
}
diff --git a/drivers/media/video/msmb/sensor/msm_sensor.c b/drivers/media/video/msmb/sensor/msm_sensor.c
index 1f54951..78c3207 100644
--- a/drivers/media/video/msmb/sensor/msm_sensor.c
+++ b/drivers/media/video/msmb/sensor/msm_sensor.c
@@ -783,7 +783,7 @@
int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
- int32_t rc = 0, index = 0, clk_index = 0;
+ int32_t rc = 0, index = 0;
struct msm_sensor_power_setting_array *power_setting_array = NULL;
struct msm_sensor_power_setting *power_setting = NULL;
struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
@@ -900,17 +900,22 @@
return 0;
power_up_failed:
pr_err("%s:%d failed\n", __func__, __LINE__);
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
+ s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+ s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
+ }
+
for (index--; index >= 0; index--) {
CDBG("%s index %d\n", __func__, index);
power_setting = &power_setting_array->power_setting[index];
CDBG("%s type %d\n", __func__, power_setting->seq_type);
switch (power_setting->seq_type) {
case SENSOR_CLK:
- for (clk_index--; clk_index >= 0; clk_index--)
- msm_cam_clk_enable(s_ctrl->dev,
- &s_ctrl->clk_info[clk_index],
- (struct clk **)&power_setting->data[0],
- 1, 0);
+ msm_cam_clk_enable(s_ctrl->dev,
+ &s_ctrl->clk_info[0],
+ (struct clk **)&power_setting->data[0],
+ s_ctrl->clk_info_size,
+ 0);
break;
case SENSOR_GPIO:
gpio_set_value_cansleep(
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 4012fec..3222ea0 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -259,6 +259,7 @@
"Single",
"Max Macroblocks",
"Max Bytes",
+ "GOB",
NULL,
};
static const char * const entropy_mode[] = {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index cc021c0..8953475 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -881,6 +881,7 @@
dev_set_drvdata(&client->dev, wcd9xxx);
wcd9xxx->dev = &client->dev;
wcd9xxx->reset_gpio = pdata->reset_gpio;
+ wcd9xxx->slim_device_bootup = true;
if (client->dev.of_node)
wcd9xxx->mclk_rate = pdata->mclk_rate;
ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index df4a241..c6d08d1 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
- * Copyright (c) 2010-2012, Code Aurora Forum. 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 as
@@ -164,7 +164,7 @@
/* de-vote clock */
if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
- clk_disable(haptic->pwm_clk);
+ clk_disable_unprepare(haptic->pwm_clk);
haptic->clk_on = false;
}
/* check for board specific clk callback */
@@ -181,7 +181,7 @@
dis_clk:
if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
- clk_disable(haptic->pwm_clk);
+ clk_disable_unprepare(haptic->pwm_clk);
haptic->clk_on = false;
}
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 295c55c..83f486c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -746,6 +746,112 @@
return 0;
}
+/* support for 9 new rmnet ports */
+#define RMNET_REV_DEVICE_COUNT (9)
+static struct net_device *netdevs_rev[RMNET_REV_DEVICE_COUNT];
+static struct platform_driver bam_rmnet_rev_drivers[RMNET_REV_DEVICE_COUNT];
+
+static int bam_rmnet_rev_probe(struct platform_device *pdev)
+{
+ int i;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ struct rmnet_private *p;
+
+ for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+ scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (i+BAM_DMUX_DATA_REV_RMNET_0));
+ if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+ break;
+ }
+
+ if (i >= RMNET_REV_DEVICE_COUNT) {
+ pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+ return 0;
+ }
+
+ p = netdev_priv(netdevs_rev[i]);
+ if (p->in_reset) {
+ p->in_reset = 0;
+ msm_bam_dmux_open(p->ch_id, netdevs_rev[i], bam_notify);
+ netif_carrier_on(netdevs_rev[i]);
+ netif_start_queue(netdevs_rev[i]);
+ }
+
+ return 0;
+}
+
+static int bam_rmnet_rev_remove(struct platform_device *pdev)
+{
+ int i;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ struct rmnet_private *p;
+
+ for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+ scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (i+BAM_DMUX_DATA_REV_RMNET_0));
+ if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+ break;
+ }
+
+ if (i >= RMNET_REV_DEVICE_COUNT) {
+ pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+ return 0;
+ }
+
+ p = netdev_priv(netdevs_rev[i]);
+ p->in_reset = 1;
+ if (p->waiting_for_ul_skb != NULL) {
+ dev_kfree_skb_any(p->waiting_for_ul_skb);
+ p->waiting_for_ul_skb = NULL;
+ }
+ msm_bam_dmux_close(p->ch_id);
+ netif_carrier_off(netdevs_rev[i]);
+ netif_stop_queue(netdevs_rev[i]);
+ return 0;
+}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+ struct device *d;
+ d = &(dev->dev);
+ return device_create_file(d, &dev_attr_timeout_suspend);
+}
+#else
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+ return 0;
+}
+#endif
+static int rmnet_debug_init(struct net_device *dev)
+{
+
+ struct device *d;
+ struct rmnet_private *p;
+ int err = 0;
+ d = &(dev->dev);
+ p = netdev_priv(dev);
+ p->timeout_us = 0;
+ p->wakeups_xmit = p->wakeups_rcv = 0;
+ err = device_create_file(d, &dev_attr_timeout);
+ if (err)
+ return err;
+ err = device_create_file(d, &dev_attr_wakeups_xmit);
+ if (err)
+ return err;
+ err = device_create_file(d, &dev_attr_wakeups_rcv);
+ if (err)
+ return err;
+ err = rmnet_debug_init_timeout_suspend(dev);
+ return err;
+}
+#else
+static int rmnet_debug_init(struct net_device *dev)
+{
+ return 0;
+}
+#endif
static int __init rmnet_init(void)
{
int ret;
@@ -828,6 +934,53 @@
return ret;
}
}
+ /*Support for new rmnet ports */
+ for (n = 0; n < RMNET_REV_DEVICE_COUNT; n++) {
+ dev = alloc_netdev(sizeof(struct rmnet_private),
+ "rev_rmnet%d", rmnet_setup);
+
+ if (!dev) {
+ pr_err("%s: no memory for rev netdev %d\n",
+ __func__, n);
+ return -ENOMEM;
+ }
+
+ netdevs_rev[n] = dev;
+ d = &(dev->dev);
+ p = netdev_priv(dev);
+ /* Initial config uses Ethernet */
+ p->operation_mode = RMNET_MODE_LLP_ETH;
+ p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
+ p->waiting_for_ul_skb = NULL;
+ p->in_reset = 0;
+ spin_lock_init(&p->lock);
+ spin_lock_init(&p->tx_queue_lock);
+
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("%s: unable to register rev netdev %d rc=%d\n",
+ __func__, n, ret);
+ free_netdev(dev);
+ return ret;
+ }
+ if (rmnet_debug_init(dev))
+ continue;
+ bam_rmnet_rev_drivers[n].probe = bam_rmnet_rev_probe;
+ bam_rmnet_rev_drivers[n].remove = bam_rmnet_rev_remove;
+ tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
+ if (tempname == NULL)
+ return -ENOMEM;
+ scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (n+BAM_DMUX_DATA_REV_RMNET_0));
+ bam_rmnet_rev_drivers[n].driver.name = tempname;
+ bam_rmnet_rev_drivers[n].driver.owner = THIS_MODULE;
+ ret = platform_driver_register(&bam_rmnet_rev_drivers[n]);
+ if (ret) {
+ pr_err("%s: new rev driver registration failed n=%d rc=%d\n",
+ __func__, n, ret);
+ return ret;
+ }
+ }
return 0;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 457cbb3..fece80e 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -114,6 +114,8 @@
struct work_struct wcnssctrl_rx_work;
struct wake_lock wcnss_wake_lock;
void __iomem *msm_wcnss_base;
+ void __iomem *riva_ccu_base;
+ void __iomem *pronto_a2xb_base;
} *penv = NULL;
static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -187,65 +189,50 @@
/* wcnss_reset_intr() is invoked when host drivers fails to
* communicate with WCNSS over SMD; so logging these registers
- * helps to know WCNSS failure reason */
+ * helps to know WCNSS failure reason
+ */
void wcnss_riva_log_debug_regs(void)
{
- void __iomem *ccu_base;
void __iomem *ccu_reg;
u32 reg = 0;
- ccu_base = ioremap(MSM_RIVA_CCU_BASE, SZ_512);
- if (!ccu_base) {
- pr_err("%s: ioremap WCNSS CCU reg failed\n", __func__);
- return;
- }
-
- ccu_reg = ccu_base + CCU_INVALID_ADDR_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_INVALID_ADDR_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
- ccu_reg = ccu_base + CCU_LAST_ADDR0_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR0_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
- ccu_reg = ccu_base + CCU_LAST_ADDR1_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR1_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
- ccu_reg = ccu_base + CCU_LAST_ADDR2_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR2_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
- iounmap(ccu_base);
}
EXPORT_SYMBOL(wcnss_riva_log_debug_regs);
/* Log pronto debug registers before sending reset interrupt */
void wcnss_pronto_log_debug_regs(void)
{
- void __iomem *a2xb_base;
void __iomem *reg_addr;
u32 reg = 0;
- a2xb_base = ioremap(MSM_PRONTO_A2XB_BASE, SZ_512);
- if (!a2xb_base) {
- pr_err("%s: ioremap WCNSS A2XB reg failed\n", __func__);
- return;
- }
-
- reg_addr = a2xb_base + A2XB_CFG_OFFSET;
+ reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
- reg_addr = a2xb_base + A2XB_INT_SRC_OFFSET;
+ reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: A2XB_INT_SRC_OFFSET %08x\n", __func__, reg);
- reg_addr = a2xb_base + A2XB_ERR_INFO_OFFSET;
+ reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
- iounmap(a2xb_base);
}
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
@@ -863,8 +850,26 @@
goto fail_wake;
}
+ if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
+ penv->riva_ccu_base = ioremap(MSM_RIVA_CCU_BASE, SZ_512);
+ if (!penv->riva_ccu_base) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wcnss physical failed\n", __func__);
+ goto fail_ioremap;
+ }
+ } else {
+ penv->pronto_a2xb_base = ioremap(MSM_PRONTO_A2XB_BASE, SZ_512);
+ if (!penv->pronto_a2xb_base) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wcnss physical failed\n", __func__);
+ goto fail_ioremap;
+ }
+ }
+
return 0;
+fail_ioremap:
+ iounmap(penv->msm_wcnss_base);
fail_wake:
wake_lock_destroy(&penv->wcnss_wake_lock);
fail_res:
@@ -936,8 +941,7 @@
#ifdef MODULE
- /*
- * Since we were built as a module, we are running because
+ /* Since we were built as a module, we are running because
* the module was loaded, therefore we assume userspace
* applications are available to service PIL, so we can
* trigger the WCNSS configuration now
@@ -947,8 +951,7 @@
#else
- /*
- * Since we were built into the kernel we'll be called as part
+ /* Since we were built into the kernel we'll be called as part
* of kernel initialization. We don't know if userspace
* applications are available to service PIL at this time
* (they probably are not), so we simply create a device node
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index a1ff7cb..7716ccb 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -1049,6 +1049,13 @@
else {
pipe->sys.desc_cache =
vmalloc(pipe->desc_size + size);
+
+ if (pipe->sys.desc_cache == NULL) {
+ SPS_ERR("sps:No memory for pipe %d of BAM 0x%x",
+ pipe_index, BAM_ID(dev));
+ return -ENOMEM;
+ }
+
memset(pipe->sys.desc_cache, 0, pipe->desc_size + size);
}
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a808e0b..c841575 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -273,8 +273,8 @@
ret = sps_phy2h(usb_phy_addr, &usb_handle);
if (ret) {
pr_err("%s: sps_phy2h failed (HSUSB/HSIC BAM) %d\n",
- __func__, ret);
- goto get_config_failed;
+ __func__, ret);
+ return ret;
}
/* IPA input parameters */
@@ -284,8 +284,39 @@
ipa_in_params.notify = connection_params->notify;
ipa_in_params.priv = connection_params->priv;
ipa_in_params.client = connection_params->client;
- if (pipe_connection->mem_type != SYSTEM_MEM)
- ipa_in_params.pipe_mem_preferred = true;
+
+ /* If BAM is using dedicated SPS pipe memory, get it */
+
+ if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+ pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
+ ret = sps_setup_bam2bam_fifo(
+ &data_mem_buf[conn_idx][pipe_dir],
+ pipe_connection->data_fifo_base_offset,
+ pipe_connection->data_fifo_size, 1);
+ if (ret) {
+ pr_err("%s: data fifo setup failure %d\n", __func__,
+ ret);
+ return ret;
+ }
+
+ ret = sps_setup_bam2bam_fifo(
+ &desc_mem_buf[conn_idx][pipe_dir],
+ pipe_connection->desc_fifo_base_offset,
+ pipe_connection->desc_fifo_size, 1);
+ if (ret) {
+ pr_err("%s: desc. fifo setup failure %d\n", __func__,
+ ret);
+ return ret;
+ }
+
+ } else {
+ pr_err("%s: unsupported memory type(%d)\n",
+ __func__, pipe_connection->mem_type);
+ return -EINVAL;
+ }
+
+ ipa_in_params.desc = desc_mem_buf[conn_idx][pipe_dir];
+ ipa_in_params.data = data_mem_buf[conn_idx][pipe_dir];
memcpy(&ipa_in_params.ipa_ep_cfg, &connection_params->ipa_ep_cfg,
sizeof(struct ipa_ep_cfg));
@@ -306,7 +337,7 @@
ret = sps_get_config(*pipe, connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
- goto get_config_failed;
+ goto free_sps_endpoints;
}
if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
@@ -344,7 +375,7 @@
error:
sps_disconnect(*pipe);
-get_config_failed:
+free_sps_endpoints:
sps_free_endpoint(*pipe);
disconnect_ipa:
ipa_disconnect(clnt_hdl);
@@ -894,6 +925,14 @@
return 0;
}
+static u8 qdss_conn_num;
+
+u8 usb_bam_get_qdss_num(void)
+{
+ return qdss_conn_num;
+}
+EXPORT_SYMBOL(usb_bam_get_qdss_num);
+
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
@@ -943,6 +982,9 @@
pdata->ignore_core_reset_ack = of_property_read_bool(node,
"qcom,ignore-core-reset-ack");
+ pdata->disable_clk_gating = of_property_read_bool(node,
+ "qcom,disable-clk-gating");
+
for_each_child_of_node(pdev->dev.of_node, node)
pipe_entry++;
@@ -1013,6 +1055,11 @@
!strcmp(str, "usb-to-peri-qdss-hsusb") ||
!strcmp(str, "peri-to-usb-qdss-hsusb"))
conn_num = 0;
+ else if (!strcmp(str, "usb-to-qdss-hsusb") ||
+ !strcmp(str, "qdss-to-usb-hsusb")) {
+ conn_num = 1;
+ qdss_conn_num = 1;
+ }
else
goto err;
@@ -1047,6 +1094,8 @@
struct resource *res, *ram_resource;
int irq;
+ qdss_conn_num = 0;
+
res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
bam_enable_strings[pdata->usb_active_bam]);
if (!res) {
@@ -1103,6 +1152,8 @@
*/
if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
usb_props.options = SPS_BAM_NO_EXT_P_RST;
+ if (pdata->disable_clk_gating)
+ usb_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
ret = sps_register_bam_device(&usb_props, &h_bam);
if (ret < 0) {
diff --git a/drivers/power/bq28400_battery.c b/drivers/power/bq28400_battery.c
index 1852687..beab4e2 100644
--- a/drivers/power/bq28400_battery.c
+++ b/drivers/power/bq28400_battery.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
@@ -136,6 +136,8 @@
struct power_supply batt_psy;
struct power_supply *dc_psy;
bool is_charging_enabled;
+ u32 temp_cold; /* in degree celsius */
+ u32 temp_hot; /* in degree celsius */
};
static struct bq28400_device *bq28400_dev;
@@ -486,10 +488,14 @@
int rsoc;
s16 current_ma = 0;
u16 battery_status;
+ int temperature;
+ struct bq28400_device *dev = i2c_get_clientdata(client);
battery_status = bq28400_read_reg(client, SBS_BATTERY_STATUS);
rsoc = bq28400_read_rsoc(client);
current_ma = bq28400_read_current(client);
+ temperature = bq28400_read_temperature(client);
+ temperature = temperature / 10; /* in degree celsius */
if (battery_status & BAT_STATUS_EMPTY)
pr_debug("Battery report Empty.\n");
@@ -513,8 +519,11 @@
return POWER_SUPPLY_STATUS_FULL;
}
- /* Enable charging when battery is not full */
- bq28400_enable_charging(bq28400_dev, true);
+ /* Enable charging when battery is not full and temperature is ok */
+ if ((temperature > dev->temp_cold) && (temperature < dev->temp_hot))
+ bq28400_enable_charging(bq28400_dev, true);
+ else
+ bq28400_enable_charging(bq28400_dev, false);
/*
* Positive current indicates charging
@@ -825,6 +834,12 @@
const struct i2c_device_id *id)
{
int ret = 0;
+ struct device_node *dev_node = client->dev.of_node;
+
+ if (dev_node == NULL) {
+ pr_err("Device Tree node doesn't exist.\n");
+ return -ENODEV;
+ }
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -843,6 +858,23 @@
return -ENOMEM;
}
+ /* Note: Lithium-ion battery normal temperature range 0..40 C */
+ ret = of_property_read_u32(dev_node, "ti,temp-cold",
+ &(bq28400_dev->temp_cold));
+ if (ret) {
+ pr_err("Unable to read cold temperature. ret=%d.\n", ret);
+ goto err_dev_node;
+ }
+ pr_debug("cold temperature limit = %d C.\n", bq28400_dev->temp_cold);
+
+ ret = of_property_read_u32(dev_node, "ti,temp-hot",
+ &(bq28400_dev->temp_hot));
+ if (ret) {
+ pr_err("Unable to read hot temperature. ret=%d.\n", ret);
+ goto err_dev_node;
+ }
+ pr_debug("hot temperature limit = %d C.\n", bq28400_dev->temp_hot);
+
bq28400_dev->client = client;
i2c_set_clientdata(client, bq28400_dev);
@@ -864,7 +896,7 @@
schedule_delayed_work(&bq28400_dev->periodic_user_space_update_work,
msecs_to_jiffies(1000));
- pr_info("Device is ready.\n");
+ pr_debug("Device is ready.\n");
return 0;
@@ -873,6 +905,7 @@
debugfs_remove_recursive(bq28400_dev->dent);
power_supply_unregister(&bq28400_dev->batt_psy);
err_register_psy:
+err_dev_node:
kfree(bq28400_dev);
bq28400_dev = NULL;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index ed57f2c..3b2e57f 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -162,6 +162,9 @@
int low_voltage_calc_ms;
int imax_ua;
struct wake_lock soc_wake_lock;
+ int disable_flat_portion_ocv;
+ int ocv_dis_high_soc;
+ int ocv_dis_low_soc;
};
/*
@@ -724,6 +727,90 @@
}
return reg & WD_BIT;
}
+
+#define IBAT_TOL_MASK 0x0F
+#define OCV_TOL_MASK 0xF0
+#define IBAT_TOL_DEFAULT 0x03
+#define IBAT_TOL_NOCHG 0x0F
+#define OCV_TOL_DEFAULT 0x20
+#define OCV_TOL_NO_OCV 0x00
+static int pm8921_bms_stop_ocv_updates(void)
+{
+ if (!the_chip) {
+ pr_err("BMS driver has not been initialized yet!\n");
+ return -EINVAL;
+ }
+ pr_debug("stopping ocv updates\n");
+ return pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+ OCV_TOL_MASK, OCV_TOL_NO_OCV);
+}
+
+static int pm8921_bms_start_ocv_updates(void)
+{
+ if (!the_chip) {
+ pr_err("BMS driver has not been initialized yet!\n");
+ return -EINVAL;
+ }
+ pr_debug("starting ocv updates\n");
+ return pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+ OCV_TOL_MASK, OCV_TOL_DEFAULT);
+}
+
+static int reset_bms_for_test(void)
+{
+ int ibat_ua, vbat_uv, rc;
+ int ocv_est_uv;
+
+ if (!the_chip) {
+ pr_err("BMS driver has not been initialized yet!\n");
+ return -EINVAL;
+ }
+
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+
+ ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000;
+ pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
+ the_chip->last_ocv_uv = ocv_est_uv;
+ last_soc = -EINVAL;
+ reset_cc(the_chip);
+ the_chip->last_cc_uah = 0;
+ pm8921_bms_stop_ocv_updates();
+
+ pr_debug("bms reset to ocv = %duv vbat_ua = %d ibat_ua = %d\n",
+ the_chip->last_ocv_uv, vbat_uv, ibat_ua);
+
+ return rc;
+}
+
+static int bms_reset_set(const char *val, const struct kernel_param *kp)
+{
+ int rc;
+
+ rc = param_set_bool(val, kp);
+ if (rc) {
+ pr_err("Unable to set bms_reset: %d\n", rc);
+ return rc;
+ }
+
+ if (*val == 'Y') {
+ rc = reset_bms_for_test();
+ if (rc) {
+ pr_err("Unable to modify bms_reset: %d\n", rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static struct kernel_param_ops bms_reset_ops = {
+ .set = bms_reset_set,
+ .get = param_get_bool,
+};
+
+static bool bms_reset;
+module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
/*
* This reflects what should the CC readings should be for
* a 5mAh discharge. This value is dependent on
@@ -1209,6 +1296,12 @@
iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
}
+ /*
+ * if we're in bms reset mode, force uuc to be 3% of fcc
+ */
+ if (bms_reset)
+ return (fcc_uah * 3) / 100;
+
uuc_uah_iavg = calculate_termination_uuc(chip,
batt_temp, chargecycles,
fcc_uah, iavg_ma,
@@ -1560,6 +1653,12 @@
(s64)fcc_uah - uuc_uah);
soc_est = bound_soc(soc_est);
+ /* never adjust during bms reset mode */
+ if (bms_reset) {
+ pr_debug("bms reset mode, SOC adjustment skipped\n");
+ goto out;
+ }
+
if (ibat_ua < 0 && pm8921_is_batfet_closed()) {
soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua,
batt_temp, chargecycles,
@@ -2058,6 +2157,15 @@
calculated_soc = new_calculated_soc;
firsttime = 0;
get_current_time(&chip->last_recalc_time);
+
+ if (chip->disable_flat_portion_ocv) {
+ if (is_between(chip->ocv_dis_high_soc, chip->ocv_dis_low_soc,
+ calculated_soc)) {
+ pm8921_bms_stop_ocv_updates();
+ } else {
+ pm8921_bms_start_ocv_updates();
+ }
+ }
return calculated_soc;
}
@@ -2082,9 +2190,10 @@
static void calculate_soc_work(struct work_struct *work)
{
- struct pm8921_bms_chip *chip = container_of(work,
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct pm8921_bms_chip *chip = container_of(dwork,
struct pm8921_bms_chip,
- calculate_soc_delayed_work.work);
+ calculate_soc_delayed_work);
recalculate_soc(chip);
schedule_delayed_work(&chip->calculate_soc_delayed_work,
@@ -2286,13 +2395,6 @@
return calculate_fcc_uah(the_chip, batt_temp, last_chargecycles);
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
-
-#define IBAT_TOL_MASK 0x0F
-#define OCV_TOL_MASK 0xF0
-#define IBAT_TOL_DEFAULT 0x03
-#define IBAT_TOL_NOCHG 0x0F
-#define OCV_TOL_DEFAULT 0x20
-#define OCV_TOL_NO_OCV 0x00
void pm8921_bms_charging_began(void)
{
struct pm8921_soc_params raw;
@@ -2419,22 +2521,6 @@
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
-int pm8921_bms_stop_ocv_updates(struct pm8921_bms_chip *chip)
-{
- pr_debug("stopping ocv updates\n");
- return pm_bms_masked_write(chip, BMS_TOLERANCES,
- OCV_TOL_MASK, OCV_TOL_NO_OCV);
-}
-EXPORT_SYMBOL_GPL(pm8921_bms_stop_ocv_updates);
-
-int pm8921_bms_start_ocv_updates(struct pm8921_bms_chip *chip)
-{
- pr_debug("stopping ocv updates\n");
- return pm_bms_masked_write(chip, BMS_TOLERANCES,
- OCV_TOL_MASK, OCV_TOL_DEFAULT);
-}
-EXPORT_SYMBOL_GPL(pm8921_bms_start_ocv_updates);
-
static irqreturn_t pm8921_bms_sbi_write_ok_handler(int irq, void *data)
{
pr_debug("irq = %d triggered", irq);
@@ -2774,10 +2860,10 @@
switch (param) {
case STOP_OCV:
- pm8921_bms_stop_ocv_updates(the_chip);
+ pm8921_bms_stop_ocv_updates();
break;
case START_OCV:
- pm8921_bms_start_ocv_updates(the_chip);
+ pm8921_bms_start_ocv_updates();
break;
default:
ret = -EINVAL;
@@ -3056,6 +3142,10 @@
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->enable_fcc_learning = pdata->enable_fcc_learning;
+ chip->disable_flat_portion_ocv = pdata->disable_flat_portion_ocv;
+ chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
+ chip->ocv_dis_low_soc = pdata->ocv_dis_low_soc;
+
mutex_init(&chip->calib_mutex);
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 2e75fcc..6ae06e9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1947,6 +1947,9 @@
if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
usb_target_ma = mA;
+ if (usb_target_ma)
+ usb_target_ma = mA;
+
spin_lock_irqsave(&vbus_lock, flags);
if (the_chip) {
if (mA > USB_WALL_THRESHOLD_MA)
@@ -2907,6 +2910,8 @@
/* only increase iusb_max if vin loop not active */
if (usb_ma < usb_target_ma) {
increase_usb_ma_value(&usb_ma);
+ if (usb_ma > usb_target_ma)
+ usb_ma = usb_target_ma;
__pm8921_charger_vbus_draw(usb_ma);
pr_debug("usb_now=%d, usb_target = %d\n",
usb_ma, usb_target_ma);
@@ -3994,8 +3999,6 @@
#define ENUM_TIMER_STOP_BIT BIT(1)
#define BOOT_DONE_BIT BIT(6)
-#define BOOT_TIMER_EN_BIT BIT(1)
-#define BOOT_DONE_MASK (BOOT_DONE_BIT | BOOT_TIMER_EN_BIT)
#define CHG_BATFET_ON_BIT BIT(3)
#define CHG_VCP_EN BIT(0)
#define CHG_BAT_TEMP_DIS_BIT BIT(2)
@@ -4018,7 +4021,7 @@
detect_battery_removal(chip);
rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
- BOOT_DONE_MASK, BOOT_DONE_MASK);
+ BOOT_DONE_BIT, BOOT_DONE_BIT);
if (rc) {
pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
return rc;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index bfc5eea..7e37daa 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -80,6 +80,7 @@
int eoc_irq;
int r_sense_uohm;
struct delayed_work calib_ccadc_work;
+ struct mutex calib_mutex;
};
static struct pm8xxx_ccadc_chip *the_chip;
@@ -378,11 +379,12 @@
return;
}
+ mutex_lock(&the_chip->calib_mutex);
rc = pm8xxx_readb(the_chip->dev->parent,
ADC_ARB_SECP_CNTRL, &sec_cntrl);
if (rc < 0) {
pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
- return;
+ goto calibration_unlock;
}
rc = calib_ccadc_enable_arbiter(the_chip);
@@ -514,6 +516,8 @@
pr_debug("error = %d programming gain trim\n", rc);
bail:
pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
+calibration_unlock:
+ mutex_unlock(&the_chip->calib_mutex);
}
EXPORT_SYMBOL(pm8xxx_calib_ccadc);
@@ -733,6 +737,7 @@
chip->r_sense_uohm = pdata->r_sense_uohm;
chip->calib_delay_ms = pdata->calib_delay_ms;
chip->batt_temp_channel = pdata->ccadc_cdata.batt_temp_channel;
+ mutex_init(&chip->calib_mutex);
calib_ccadc_read_offset_and_gain(chip,
&chip->ccadc_gain_uv,
@@ -756,6 +761,7 @@
return 0;
free_chip:
+ mutex_destroy(&chip->calib_mutex);
kfree(chip);
return rc;
}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 8002e9e..63cab43 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -34,6 +34,8 @@
/* Coulomb counter clear registers */
#define BMS1_CC_DATA_CTL 0x42
#define BMS1_CC_CLEAR_CTL 0x43
+/* BMS Tolerances */
+#define BMS1_TOL_CTL 0X44
/* OCV limit registers */
#define BMS1_OCV_USE_LOW_LIMIT_THR0 0x48
#define BMS1_OCV_USE_LOW_LIMIT_THR1 0x49
@@ -203,6 +205,7 @@
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
+static bool bms_reset;
static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
u16 base, int count)
@@ -889,6 +892,12 @@
chip->iavg_num_samples);
}
+ /*
+ * if we're in bms reset mode, force uuc to be 3% of fcc
+ */
+ if (bms_reset)
+ return (params->fcc_uah * 3) / 100;
+
uuc_uah_iavg = calculate_termination_uuc(chip, params, uuc_iavg_ma,
batt_temp, &pc_unusable);
pr_debug("uuc_iavg_ma = %d uuc with iavg = %d\n",
@@ -1177,6 +1186,76 @@
return soc;
}
+#define IBAT_TOL_MASK 0x0F
+#define OCV_TOL_MASK 0xF0
+#define IBAT_TOL_DEFAULT 0x03
+#define IBAT_TOL_NOCHG 0x0F
+#define OCV_TOL_DEFAULT 0x20
+#define OCV_TOL_NO_OCV 0x00
+static int stop_ocv_updates(struct qpnp_bms_chip *chip)
+{
+ pr_debug("stopping ocv updates\n");
+ return qpnp_masked_write(chip, BMS1_TOL_CTL,
+ OCV_TOL_MASK, OCV_TOL_NO_OCV);
+}
+
+static int reset_bms_for_test(struct qpnp_bms_chip *chip)
+{
+ int ibat_ua, vbat_uv, rc;
+ int ocv_est_uv;
+
+ if (!chip) {
+ pr_err("BMS driver has not been initialized yet!\n");
+ return -EINVAL;
+ }
+
+ rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
+
+ ocv_est_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
+ pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
+ chip->last_ocv_uv = ocv_est_uv;
+ chip->last_soc = -EINVAL;
+ reset_cc(chip);
+ chip->last_cc_uah = INT_MIN;
+ stop_ocv_updates(chip);
+
+ pr_debug("bms reset to ocv = %duv vbat_ua = %d ibat_ua = %d\n",
+ chip->last_ocv_uv, vbat_uv, ibat_ua);
+
+ return rc;
+}
+
+static int bms_reset_set(const char *val, const struct kernel_param *kp)
+{
+ int rc;
+
+ rc = param_set_bool(val, kp);
+ if (rc) {
+ pr_err("Unable to set bms_reset: %d\n", rc);
+ return rc;
+ }
+
+ if (*(bool *)kp->arg) {
+ struct power_supply *bms_psy = power_supply_get_by_name("bms");
+ struct qpnp_bms_chip *chip = container_of(bms_psy,
+ struct qpnp_bms_chip, bms_psy);
+
+ rc = reset_bms_for_test(chip);
+ if (rc) {
+ pr_err("Unable to modify bms_reset: %d\n", rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static struct kernel_param_ops bms_reset_ops = {
+ .set = bms_reset_set,
+ .get = param_get_bool,
+};
+
+module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
+
static int charging_adjustments(struct qpnp_bms_chip *chip,
struct soc_params *params, int soc,
int vbat_uv, int ibat_ua, int batt_temp)
@@ -1268,6 +1347,12 @@
(s64)params->fcc_uah - params->uuc_uah);
soc_est = bound_soc(soc_est);
+ /* never adjust during bms reset mode */
+ if (bms_reset) {
+ pr_debug("bms reset mode, SOC adjustment skipped\n");
+ goto out;
+ }
+
if (ibat_ua < 0 && !is_batfet_open(chip)) {
soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
batt_temp);
@@ -1631,6 +1716,8 @@
chg_time_sec = DIV_ROUND_UP(chip->charge_time_us, USEC_PER_SEC);
catch_up_sec = DIV_ROUND_UP(chip->catch_up_time_us, USEC_PER_SEC);
+ if (catch_up_sec == 0)
+ return new_soc;
pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
/*
@@ -1730,8 +1817,7 @@
}
/* last_soc < soc ... scale and catch up */
- if (chip->last_soc != -EINVAL && chip->last_soc < soc
- && soc != 100 && chip->catch_up_time_us != 0)
+ if (chip->last_soc != -EINVAL && chip->last_soc < soc && soc != 100)
soc = scale_soc_while_chg(chip, delta_time_us,
soc, chip->last_soc);
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index d4fb02b..9b0b8b4 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1061,7 +1061,7 @@
dev_err(dev->dev, "rx thread wait error:%d", ret);
/* 1 irq notification per message */
- if (!dev->use_rx_msgqs) {
+ if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
msm_slim_rxwq(dev);
continue;
}
@@ -1255,9 +1255,9 @@
spin_lock_init(&dev->rx_lock);
dev->ee = 1;
if (rxreg_access)
- dev->use_rx_msgqs = 0;
+ dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
else
- dev->use_rx_msgqs = 1;
+ dev->use_rx_msgqs = MSM_MSGQ_RESET;
dev->irq = irq->start;
dev->bam.irq = bam_irq->start;
@@ -1328,7 +1328,7 @@
* Manager register initialization
* If RX msg Q is used, disable RX_MSG_RCVD interrupt
*/
- if (dev->use_rx_msgqs)
+ if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
writel_relaxed((MGR_INT_RECFG_DONE | MGR_INT_TX_NACKED_2 |
MGR_INT_MSG_BUF_CONTE | /* MGR_INT_RX_MSG_RCVD | */
MGR_INT_TX_MSG_SENT), dev->base + MGR_INT_EN);
@@ -1357,7 +1357,7 @@
mb();
/* Enable RX msg Q */
- if (dev->use_rx_msgqs)
+ if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
writel_relaxed(MGR_CFG_ENABLE | MGR_CFG_RX_MSGQ_EN,
dev->base + MGR_CFG);
else
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index a37a7803..eb741ef 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -129,7 +129,7 @@
* queuing work
*/
mb();
- if (dev->use_rx_msgqs)
+ if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
dev_err(dev->dev,
"direct message received even with RX MSGQs");
else
@@ -225,8 +225,17 @@
u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
if (txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
- SLIM_MSG_MC_RECONFIGURE_NOW))
- return msm_slim_qmi_power_request(dev, false);
+ 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;
+ }
else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
return 0;
@@ -543,7 +552,7 @@
return ret;
txn.len = 0;
}
- return ret;
+ return 0;
}
static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
@@ -581,6 +590,24 @@
return ret;
}
+static void ngd_slim_setup_rx_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,
+ &dev->rx_msgq_notify);
+ if (!ret)
+ dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+ else
+ pr_err("RX msgq not being used:%d", ret);
+ }
+}
static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
{
u8 mc, mt, len;
@@ -608,12 +635,9 @@
txn.wbuf = wbuf;
txn.len = 4;
pr_info("SLIM SAT: Received master capability");
- if (dev->state == MSM_CTRL_DOWN) {
- dev->use_rx_msgqs = 1;
- msm_slim_sps_init(dev, dev->bam_mem,
- NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS,
- true);
- if (dev->use_rx_msgqs)
+ if (dev->state >= MSM_CTRL_ASLEEP) {
+ ngd_slim_setup_rx_path(dev);
+ if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
msgq_en |= NGD_CFG_RX_MSGQ_EN;
writel_relaxed(msgq_en, dev->base +
NGD_BASE(dev->ctrl.nr, dev->ver));
@@ -691,8 +715,7 @@
int timeout, ret;
enum msm_ctrl_state cur_state = dev->state;
u32 laddr;
- u32 msgq_en = 1;
- u32 ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
+ u32 ngd_int = (NGD_INT_TX_NACKED_2 |
NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
@@ -721,12 +744,11 @@
* ADSP power collapse case, where HW wasn't reset.
* Reconnect BAM pipes if disconnected
*/
+ ngd_slim_setup_rx_path(dev);
return 0;
} else if (cur_state != MSM_CTRL_DOWN) {
pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
dev->state, laddr);
- if (dev->use_rx_msgqs)
- msgq_en |= NGD_CFG_RX_MSGQ_EN;
}
/*
@@ -739,7 +761,7 @@
* Enable NGD. Configure NGD in register acc. mode until master
* announcement is received
*/
- writel_relaxed(msgq_en, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+ writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
/* make sure NGD enabling goes through */
mb();
@@ -815,7 +837,7 @@
continue;
}
/* 1 irq notification per message */
- if (!dev->use_rx_msgqs) {
+ if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
msm_slim_rx_dequeue(dev, (u8 *)buffer);
ngd_slim_rx(dev, (u8 *)buffer);
continue;
@@ -879,7 +901,6 @@
ngd_slim_enable(dev, false);
/* disconnect BAM pipes */
msm_slim_sps_exit(dev, false);
- dev->use_rx_msgqs = 0;
mutex_lock(&ctrl->m_ctrl);
/* device up should be called again after SSR */
list_for_each_entry(sbdev, &ctrl->devs, dev_list)
@@ -908,6 +929,7 @@
struct resource *slim_mem;
struct resource *irq, *bam_irq;
enum apr_subsys_state q6_state;
+ bool rxreg_access = false;
q6_state = apr_get_q6_state();
if (q6_state == APR_SUBSYS_DOWN) {
@@ -970,6 +992,8 @@
dev_err(&pdev->dev, "Cell index not specified:%d", ret);
goto err_ctrl_failed;
}
+ rxreg_access = of_property_read_bool(pdev->dev.of_node,
+ "qcom,rxreg-access");
} else {
dev->ctrl.nr = pdev->id;
}
@@ -1000,6 +1024,10 @@
dev->irq = irq->start;
dev->bam.irq = bam_irq->start;
+ if (rxreg_access)
+ dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
+ else
+ dev->use_rx_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 72a8669..3e19f9b 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
#include <linux/slimbus/slimbus.h>
@@ -378,53 +377,19 @@
return ret;
}
-static int msm_slim_init_rx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
+int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ struct completion *notify)
{
int i, ret;
- u32 pipe_offset;
- 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 completion *notify = &dev->rx_msgq_notify;
-
struct sps_register_event sps_error_event; /* SPS_ERROR */
struct sps_register_event sps_descr_event; /* DESCR_DONE */
-
- init_completion(notify);
- if (!dev->use_rx_msgqs)
- 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;
- dev_dbg(dev->dev, "Message queue pipe offset %d\n", pipe_offset);
-
- config->mode = SPS_MODE_SRC;
- config->source = dev->bam.hdl;
- config->destination = SPS_DEV_HANDLE_MEM;
- config->src_pipe_index = pipe_offset;
- config->options = SPS_O_DESC_DONE | SPS_O_ERROR |
- SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
-
- /* Allocate memory for the FIFO descriptors */
- ret = msm_slim_sps_mem_alloc(dev, descr,
- MSM_SLIM_DESC_NUM * sizeof(struct sps_iovec));
- if (ret) {
- dev_err(dev->dev, "unable to allocate SPS descriptors\n");
- goto alloc_descr_failed;
- }
+ struct sps_connect *config = &endpoint->config;
ret = sps_connect(endpoint->sps, config);
if (ret) {
dev_err(dev->dev, "sps_connect failed 0x%x\n", ret);
- goto sps_connect_failed;
+ return ret;
}
memset(&sps_descr_event, 0x00, sizeof(sps_descr_event));
@@ -453,13 +418,6 @@
goto sps_reg_event_failed;
}
- /* Allocate memory for the message buffer(s), N descrs, 4-byte mesg */
- ret = msm_slim_sps_mem_alloc(dev, mem, MSM_SLIM_DESC_NUM * 4);
- if (ret) {
- dev_err(dev->dev, "dma_alloc_coherent failed\n");
- goto alloc_buffer_failed;
- }
-
/*
* Call transfer_one for each 4-byte buffer
* Use (buf->size/4) - 1 for the number of buffer to post
@@ -475,20 +433,74 @@
}
return 0;
-
sps_transfer_failed:
- msm_slim_sps_mem_free(dev, mem);
-alloc_buffer_failed:
memset(&sps_error_event, 0x00, sizeof(sps_error_event));
sps_register_event(endpoint->sps, &sps_error_event);
sps_reg_event_failed:
sps_disconnect(endpoint->sps);
-sps_connect_failed:
+ return ret;
+}
+static int msm_slim_init_rx_msgq(struct msm_slim_ctrl *dev, u32 pipe_reg)
+{
+ int ret;
+ u32 pipe_offset;
+ 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 completion *notify = &dev->rx_msgq_notify;
+
+ init_completion(notify);
+ if (dev->use_rx_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;
+ dev_dbg(dev->dev, "Message queue pipe offset %d\n", pipe_offset);
+
+ config->mode = SPS_MODE_SRC;
+ config->source = dev->bam.hdl;
+ config->destination = SPS_DEV_HANDLE_MEM;
+ config->src_pipe_index = pipe_offset;
+ config->options = SPS_O_DESC_DONE | SPS_O_ERROR |
+ SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;
+
+ /* Allocate memory for the FIFO descriptors */
+ ret = msm_slim_sps_mem_alloc(dev, descr,
+ MSM_SLIM_DESC_NUM * 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, 4-byte mesg */
+ ret = msm_slim_sps_mem_alloc(dev, mem, MSM_SLIM_DESC_NUM * 4);
+ if (ret) {
+ dev_err(dev->dev, "dma_alloc_coherent failed\n");
+ goto alloc_buffer_failed;
+ }
+
+ ret = msm_slim_connect_endp(dev, endpoint, notify);
+
+ if (!ret) {
+ dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
+ 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_rx_msgqs = 0;
+ dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
return ret;
}
@@ -550,7 +562,7 @@
ret = sps_register_bam_device(&bam_props, &bam_handle);
if (ret) {
dev_err(dev->dev, "disabling BAM: reg-bam failed 0x%x\n", ret);
- dev->use_rx_msgqs = 0;
+ dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
goto init_rx_msgq;
}
dev->bam.hdl = bam_handle;
@@ -569,7 +581,7 @@
void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
{
- if (dev->use_rx_msgqs) {
+ 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;
@@ -581,6 +593,7 @@
sps_disconnect(endpoint->sps);
msm_slim_sps_mem_free(dev, descr);
msm_slim_free_endpoint(endpoint);
+ dev->use_rx_msgqs = MSM_MSGQ_RESET;
}
if (dereg) {
sps_deregister_bam_device(dev->bam.hdl);
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 1c6db32..6e329b3 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -155,6 +155,12 @@
MSM_CTRL_DOWN,
};
+enum msm_slim_msgq {
+ MSM_MSGQ_DISABLED,
+ MSM_MSGQ_RESET,
+ MSM_MSGQ_ENABLED,
+};
+
struct msm_slim_sps_bam {
u32 hdl;
void __iomem *base;
@@ -209,7 +215,7 @@
struct clk *hclk;
struct mutex tx_lock;
u8 pgdla;
- bool use_rx_msgqs;
+ enum msm_slim_msgq use_rx_msgqs;
int pipe_b;
struct completion reconf;
bool reconf_busy;
@@ -273,6 +279,9 @@
u32 pipe_reg, bool remote);
void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg);
+int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
+ struct msm_slim_endp *endpoint,
+ struct completion *notify);
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/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 7d8defd..f6c910a 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -38,7 +38,7 @@
#include <linux/rcupdate.h>
#include <linux/notifier.h>
-static uint32_t lowmem_debug_level = 2;
+static uint32_t lowmem_debug_level = 1;
static int lowmem_adj[6] = {
0,
1,
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 14b8ca2..32c081d 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1287,8 +1287,9 @@
goto out;
}
ack_pkt->hdr.cmd = SMUX_CMD_OPEN_LCH;
- ack_pkt->hdr.flags = SMUX_CMD_OPEN_ACK
- | SMUX_CMD_OPEN_POWER_COLLAPSE;
+ ack_pkt->hdr.flags = SMUX_CMD_OPEN_ACK;
+ if (enable_powerdown)
+ ack_pkt->hdr.flags |= SMUX_CMD_OPEN_POWER_COLLAPSE;
ack_pkt->hdr.lcid = lcid;
ack_pkt->hdr.payload_len = 0;
ack_pkt->hdr.pad_len = 0;
@@ -1308,8 +1309,9 @@
if (ack_pkt) {
ack_pkt->hdr.lcid = lcid;
ack_pkt->hdr.cmd = SMUX_CMD_OPEN_LCH;
- ack_pkt->hdr.flags =
- SMUX_CMD_OPEN_POWER_COLLAPSE;
+ if (enable_powerdown)
+ ack_pkt->hdr.flags |=
+ SMUX_CMD_OPEN_POWER_COLLAPSE;
ack_pkt->hdr.payload_len = 0;
ack_pkt->hdr.pad_len = 0;
smux_tx_queue(ack_pkt, ch, 0);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 19e2151..6684fc4 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -64,6 +64,7 @@
#include <mach/dma.h>
#include <mach/sps.h>
#include <mach/msm_serial_hs.h>
+#include <mach/msm_bus.h>
#include "msm_serial_hs_hwreg.h"
#define UART_SPS_CONS_PERIPHERAL 0
@@ -211,6 +212,10 @@
* callback event object registered for an SPS connection end point.
*/
struct sps_event_notify notify;
+ /* bus client handler */
+ u32 bus_perf_client;
+ /* BLSP UART required BUS Scaling data */
+ struct msm_bus_scale_pdata *bus_scale_table;
};
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
@@ -220,6 +225,8 @@
#define UARTDM_NR 256
#define BAM_PIPE_MIN 0
#define BAM_PIPE_MAX 11
+#define BUS_SCALING 1
+#define BUS_RESET 0
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
@@ -295,6 +302,21 @@
{
return (msm_uport->uart_type == BLSP_HSUART);
}
+
+static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote)
+{
+ int ret;
+
+ if (is_blsp_uart(msm_uport) && msm_uport->bus_perf_client) {
+ pr_debug("Bus voting:%d\n", vote);
+ ret = msm_bus_scale_client_update_request(
+ msm_uport->bus_perf_client, vote);
+ if (ret)
+ pr_err("%s(): Failed for Bus voting: %d\n",
+ __func__, vote);
+ }
+}
+
static inline unsigned int msm_hs_read(struct uart_port *uport,
unsigned int offset)
{
@@ -363,6 +385,8 @@
unsigned long flags;
int ret = 0;
+ msm_hs_bus_voting(msm_uport, BUS_SCALING);
+
clk_prepare_enable(msm_uport->clk);
if (msm_uport->pclk)
clk_prepare_enable(msm_uport->pclk);
@@ -394,6 +418,7 @@
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
return 0;
}
@@ -404,6 +429,8 @@
unsigned long flags;
int ret = 0;
+ msm_hs_bus_voting(msm_uport, BUS_SCALING);
+
clk_prepare_enable(msm_uport->clk);
if (msm_uport->pclk)
clk_prepare_enable(msm_uport->pclk);
@@ -417,6 +444,8 @@
clk_disable_unprepare(msm_uport->pclk);
*val = (ret & UARTDM_MR2_LOOP_MODE_BMSK) ? 1 : 0;
+
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(loopback_enable_fops, msm_serial_loopback_enable_get,
@@ -1702,7 +1731,11 @@
wake_unlock(&msm_uport->dma_wake_lock);
spin_unlock_irqrestore(&uport->lock, flags);
+
+ /* Reset PNOC Bus Scaling */
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
mutex_unlock(&msm_uport->clk_mutex);
+
return 1;
}
@@ -1872,6 +1905,10 @@
wake_lock(&msm_uport->dma_wake_lock);
disable_irq_nosync(msm_uport->wakeup.irq);
spin_unlock_irqrestore(&uport->lock, flags);
+
+ /* Vote for PNOC BUS Scaling */
+ msm_hs_bus_voting(msm_uport, BUS_SCALING);
+
ret = clk_prepare_enable(msm_uport->clk);
if (ret) {
dev_err(uport->dev, "Clock ON Failure"
@@ -2116,6 +2153,9 @@
disable_irq(msm_uport->wakeup.irq);
}
+ /* Vote for PNOC BUS Scaling */
+ msm_hs_bus_voting(msm_uport, BUS_SCALING);
+
spin_lock_irqsave(&uport->lock, flags);
msm_hs_start_rx_locked(uport);
@@ -2555,7 +2595,7 @@
static int __devinit msm_hs_probe(struct platform_device *pdev)
{
- int ret;
+ int ret = 0;
struct uart_port *uport;
struct msm_hs_port *msm_uport;
struct resource *core_resource;
@@ -2637,6 +2677,20 @@
uport->irq = core_irqres;
msm_uport->bam_irq = bam_irqres;
+ msm_uport->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+ if (!msm_uport->bus_scale_table) {
+ pr_err("BLSP UART: Bus scaling is disabled.\n");
+ } else {
+ msm_uport->bus_perf_client =
+ msm_bus_scale_register_client
+ (msm_uport->bus_scale_table);
+ if (IS_ERR(&msm_uport->bus_perf_client)) {
+ pr_err("%s(): Bus client register failed.\n",
+ __func__);
+ ret = -EINVAL;
+ goto unmap_memory;
+ }
+ }
} else {
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2755,6 +2809,8 @@
}
}
+ msm_hs_bus_voting(msm_uport, BUS_SCALING);
+
clk_prepare_enable(msm_uport->clk);
if (msm_uport->pclk)
clk_prepare_enable(msm_uport->pclk);
@@ -2792,6 +2848,8 @@
uport->line = pdata->userid;
ret = uart_add_one_port(&msm_hs_driver, uport);
if (!ret) {
+
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
@@ -2799,6 +2857,8 @@
}
err_clock:
+
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
@@ -2907,6 +2967,10 @@
* Hence mb() requires here.
*/
mb();
+
+ /* Reset PNOC Bus Scaling */
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
+
if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
/* to balance clk_state */
clk_disable_unprepare(msm_uport->clk);
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 0b46082..6875b74 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -1,6 +1,7 @@
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
ccflags-y += -Idrivers/usb/host
+ccflags-y += -Idrivers/base/power
obj-$(CONFIG_USB_DWC3) += dwc3.o
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 1ee0828..fb785f3 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.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
@@ -1459,6 +1459,7 @@
{
int ret;
bool dcp;
+ bool host_bus_suspend;
dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
@@ -1481,17 +1482,7 @@
}
dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
-
- /* Sequence to put hardware in low power state:
- * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
- * 2. Clear charger detection control fields (performed above)
- * 3. SUSPEND PHY and turn OFF core clock after some delay
- * 4. Clear interrupt latch register and enable BSV, ID HV interrupts
- * 5. Enable PHY retention
- */
- dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000, 0x1000);
- dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
- 0xC00000, 0x800000);
+ host_bus_suspend = mdwc->host_mode == 1;
/* Sequence to put SSPHY in low power state:
* 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
@@ -1507,10 +1498,43 @@
usleep_range(1000, 1200);
clk_disable_unprepare(mdwc->ref_clk);
- dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
- dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x18000);
- if (!dcp)
+ if (host_bus_suspend) {
+ /* Sequence for host bus suspend case:
+ * 1. Set suspend and sleep bits in GUSB2PHYCONFIG reg
+ * 2. Clear interrupt latch register and enable BSV, ID HV intr
+ * 3. Enable DP and DM HV interrupts in ALT_INTERRUPT_EN_REG
+ * 4. Enable PHY retention
+ */
+ dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
+ 0x00000140);
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+ if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0x18000, 0x18000);
+ dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x00A);
dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x0);
+ udelay(5);
+ } else {
+ /* Sequence to put hardware in low power state:
+ * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
+ * 2. Clear charger detection control fields (performed above)
+ * 3. SUSPEND PHY and turn OFF core clock after some delay
+ * 4. Clear interrupt latch register and enable BSV, ID HV intr
+ * 5. Enable PHY retention
+ */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000,
+ 0x1000);
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0xC00000, 0x800000);
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+ if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0x18000, 0x18000);
+ if (!dcp)
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0x2, 0x0);
+ }
/* make sure above writes are completed before turning off clocks */
wmb();
@@ -1530,7 +1554,8 @@
dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
}
- if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp)
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
+ !host_bus_suspend)
dwc3_hsusb_ldo_enable(0);
dwc3_ssusb_ldo_enable(0);
@@ -1551,6 +1576,7 @@
{
int ret;
bool dcp;
+ bool host_bus_suspend;
dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
@@ -1575,7 +1601,9 @@
__func__, ret);
dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
- if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp)
+ host_bus_suspend = mdwc->host_mode == 1;
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
+ !host_bus_suspend)
dwc3_hsusb_ldo_enable(1);
dwc3_ssusb_ldo_enable(1);
@@ -1587,20 +1615,41 @@
clk_prepare_enable(mdwc->iface_clk);
clk_prepare_enable(mdwc->core_clk);
- /* Disable HV interrupt */
- dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x0);
- /* Disable Retention */
- dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+ if (host_bus_suspend) {
+ /* Disable HV interrupt */
+ if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0x18000, 0x0);
+ /* Clear interrupt latch register */
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0x000);
- dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
- dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) | 0xF0000000);
- /* 10usec delay required before de-asserting PHY RESET */
- udelay(10);
- dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
- dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) & 0x7FFFFFFF);
+ /* Disable DP and DM HV interrupt */
+ dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
- /* Bring PHY out of suspend */
- dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000, 0x0);
+ /* Disable Retention */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+ } else {
+ /* Disable HV interrupt */
+ if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0x18000, 0x0);
+ /* Disable Retention */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+
+ dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
+ 0xF0000000);
+ /* 10usec delay required before de-asserting PHY RESET */
+ udelay(10);
+ dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) &
+ 0x7FFFFFFF);
+
+ /* Bring PHY out of suspend */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000,
+ 0x0);
+
+ }
/* Assert SS PHY RESET */
dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
@@ -2186,22 +2235,24 @@
msm->charger.charging_disabled = of_property_read_bool(node,
"qcom,charging-disabled");
- if (!msm->ext_xceiv.otg_capability) {
- /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
- msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
- if (msm->hs_phy_irq < 0) {
- dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
- msm->hs_phy_irq = 0;
- } else {
- ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
- IRQF_TRIGGER_RISING, "msm_dwc3", msm);
- if (ret) {
- dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
- goto disable_hs_ldo;
- }
- enable_irq_wake(msm->hs_phy_irq);
- }
+ /*
+ * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
+ * DP and DM linestate transitions during low power mode.
+ */
+ msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+ if (msm->hs_phy_irq < 0) {
+ dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
+ msm->hs_phy_irq = 0;
} else {
+ ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
+ IRQF_TRIGGER_RISING, "msm_dwc3", msm);
+ if (ret) {
+ dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
+ goto disable_hs_ldo;
+ }
+ enable_irq_wake(msm->hs_phy_irq);
+ }
+ if (msm->ext_xceiv.otg_capability) {
/* Use ADC for ID pin detection */
queue_delayed_work(system_nrt_wq, &msm->init_adc_work, 0);
device_create_file(&pdev->dev, &dev_attr_adc_enable);
@@ -2439,6 +2490,12 @@
dev_dbg(dev, "dwc3-msm PM suspend\n");
+ flush_delayed_work_sync(&mdwc->resume_work);
+ if (!atomic_read(&mdwc->in_lpm)) {
+ dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n");
+ return -EBUSY;
+ }
+
ret = dwc3_msm_suspend(mdwc);
if (!ret)
atomic_set(&mdwc->pm_suspended, 1);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index eb879e3..4980337 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -1,7 +1,7 @@
/**
* dwc3_otg.c - DesignWare USB3 DRD Controller OTG
*
- * 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
@@ -55,6 +55,25 @@
}
}
+static int dwc3_otg_set_suspend(struct usb_phy *phy, int suspend)
+{
+ struct usb_otg *otg = phy->otg;
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (dotg->host_bus_suspend == suspend)
+ return 0;
+
+ dotg->host_bus_suspend = suspend;
+ if (suspend) {
+ pm_runtime_put_sync(phy->dev);
+ } else {
+ pm_runtime_get_noresume(phy->dev);
+ pm_runtime_resume(phy->dev);
+ }
+
+ return 0;
+}
+
/**
* dwc3_otg_set_host_power - Enable port power control for host operation
*
@@ -149,6 +168,14 @@
* anymore.
*/
dwc3_otg_set_host_regs(dotg);
+ /*
+ * FIXME If micro A cable is disconnected during system suspend,
+ * xhci platform device will be removed before runtime pm is
+ * enabled for xhci device. Due to this, disable_depth becomes
+ * greater than one and runtimepm is not enabled for next microA
+ * connect. Fix this by calling pm_runtime_init for xhci device.
+ */
+ pm_runtime_init(&dwc->xhci->dev);
ret = platform_device_add(dwc->xhci);
if (ret) {
dev_err(otg->phy->dev,
@@ -353,6 +380,9 @@
dev_dbg(phy->dev, "ext PHY_RESUME event received\n");
/* ext_xceiver would have taken h/w out of LPM by now */
ret = pm_runtime_get(phy->dev);
+ if ((phy->state == OTG_STATE_A_HOST) &&
+ dotg->host_bus_suspend)
+ dotg->host_bus_suspend = 0;
if (ret == -EACCES) {
/* pm_runtime_get may fail during system
resume with -EACCES error */
@@ -852,6 +882,7 @@
dotg->otg.phy->otg = &dotg->otg;
dotg->otg.phy->dev = dwc->dev;
dotg->otg.phy->set_power = dwc3_otg_set_power;
+ dotg->otg.phy->set_suspend = dwc3_otg_set_suspend;
ret = usb_set_transceiver(dotg->otg.phy);
if (ret) {
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 5a36a4f..07d6411 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -1,7 +1,7 @@
/**
* dwc3_otg.h - DesignWare USB3 DRD Controller OTG
*
- * Copyright (c) 2012, Code Aurora Forum. 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
@@ -20,6 +20,7 @@
#include <linux/power_supply.h>
#include <linux/usb/otg.h>
+#include "power.h"
#define DWC3_IDEV_CHG_MAX 1500
@@ -48,6 +49,7 @@
unsigned long inputs;
struct power_supply *psy;
struct completion dwc3_xcvr_vbus_init;
+ int host_bus_suspend;
};
/**
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 644a779..d6d8a76 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -55,7 +55,6 @@
dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
- xhci->dev.parent = dwc->dev;
xhci->dev.dma_mask = dwc->dev->dma_mask;
xhci->dev.dma_parms = dwc->dev->dma_parms;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 9d231d6..f004891 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -69,6 +69,9 @@
#include "ci13xxx_udc.h"
+/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
+static unsigned int streaming;
+module_param(streaming, uint, S_IRUGO | S_IWUSR);
/******************************************************************************
* DEFINE
@@ -332,9 +335,6 @@
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_RESET_EVENT);
- if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
- hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
/* USBMODE should be configured step by step */
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
@@ -369,7 +369,15 @@
*/
static int hw_device_state(u32 dma)
{
+ struct ci13xxx *udc = _udc;
+
if (dma) {
+ if (streaming || !(udc->udc_driver->flags &
+ CI13XXX_DISABLE_STREAMING))
+ hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
+ else
+ hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+
hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
/* interrupt, error, port change, reset, sleep/suspend */
hw_cwrite(CAP_USBINTR, ~0,
@@ -414,6 +422,10 @@
{
ktime_t start, diff;
int n = hw_ep_bit(num, dir);
+ struct ci13xxx_ep *mEp = &_udc->ci13xxx_ep[n];
+
+ if (_udc->skip_flush || list_empty(&mEp->qh.queue))
+ return 0;
start = ktime_get();
do {
@@ -428,6 +440,7 @@
__func__, num,
dir ? "IN" : "OUT");
debug_ept_flush_info(num, dir);
+ _udc->skip_flush = true;
return 0;
}
}
@@ -445,7 +458,6 @@
*/
static int hw_ep_disable(int num, int dir)
{
- hw_ep_flush(num, dir);
hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
return 0;
@@ -980,16 +992,16 @@
* dbg_done: prints a DONE event
* @addr: endpoint address
* @td: transfer descriptor
- * @status: status
*/
-static void dbg_done(u8 addr, const u32 token, int status)
+static void dbg_done(u8 addr, const struct usb_request *req)
{
char msg[DBG_DATA_MSG];
- scnprintf(msg, sizeof(msg), "%d %02X",
- (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
- (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
- dbg_print(addr, "DONE", status, msg);
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%p %d %d", req, req->actual, req->length);
+ dbg_print(addr, "DONE", req->status, msg);
+ }
}
/**
@@ -1016,7 +1028,7 @@
if (req != NULL) {
scnprintf(msg, sizeof(msg),
- "%d %d", !req->no_interrupt, req->length);
+ "%p %d %d", req, !req->no_interrupt, req->length);
dbg_print(addr, "QUEUE", status, msg);
}
}
@@ -1049,6 +1061,7 @@
{
char msg[DBG_DATA_MSG];
struct ci13xxx_req *req;
+ struct ci13xxx_td_wrapper *td;
struct list_head *ptr = NULL;
if (mep != NULL) {
@@ -1065,15 +1078,14 @@
list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
- scnprintf(msg, sizeof(msg),
- "%08X:%08X:%08X\n",
- req->dma, req->ptr->next,
- req->ptr->token);
- dbg_print(addr, "REQ", 0, msg);
- scnprintf(msg, sizeof(msg), "%08X:%d\n",
- req->ptr->page[0],
- req->req.status);
- dbg_print(addr, "REQPAGE", 0, msg);
+ list_for_each_entry(td, &req->td_list, list) {
+ scnprintf(msg, sizeof(msg),
+ "%08X:%08X:%08X:%08X\n",
+ td->dma, td->ptr->next,
+ td->ptr->token,
+ td->ptr->page[0]);
+ dbg_print(addr, "TD", 0, msg);
+ }
}
}
}
@@ -1444,6 +1456,7 @@
unsigned long flags;
struct list_head *ptr = NULL;
struct ci13xxx_req *req = NULL;
+ struct ci13xxx_td_wrapper *td;
unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
dbg_trace("[%s] %p\n", __func__, buf);
@@ -1458,15 +1471,18 @@
{
req = list_entry(ptr, struct ci13xxx_req, queue);
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: TD=%08X %s\n",
- i % hw_ep_max/2, (u32)req->dma,
- ((i < hw_ep_max/2) ? "RX" : "TX"));
-
- for (j = 0; j < qSize; j++)
+ list_for_each_entry(td, &req->td_list, list) {
n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X\n", j,
- *((u32 *)req->ptr + j));
+ "EP=%02i: TD=%08X %s\n",
+ i % hw_ep_max/2, (u32)td->dma,
+ ((i < hw_ep_max/2) ?
+ "RX" : "TX"));
+
+ for (j = 0; j < qSize; j++)
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X\n", j,
+ *((u32 *)td->ptr + j));
+ }
}
spin_unlock_irqrestore(udc->lock, flags);
@@ -1484,6 +1500,7 @@
unsigned int ep_num, dir;
int n;
struct ci13xxx_req *mReq = NULL;
+ struct ci13xxx_td_wrapper *td;
if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
dev_err(dev, "<ep_num> <dir>: prime the ep");
@@ -1497,7 +1514,8 @@
n = hw_ep_bit(mEp->num, mEp->dir);
mReq = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
- mEp->qh.ptr->td.next = mReq->dma;
+ td = list_first_entry(&mReq->td_list, struct ci13xxx_td_wrapper, list);
+ mEp->qh.ptr->td.next = td->dma;
mEp->qh.ptr->td.token &= ~TD_STATUS;
wmb();
@@ -1527,12 +1545,15 @@
int n;
struct list_head *ptr = NULL;
struct ci13xxx_req *req = NULL;
+ struct ci13xxx_td_wrapper *td;
+ unsigned long flags;
if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
dev_err(dev, "<ep_num> <dir>: to print dtds");
goto done;
}
+ spin_lock_irqsave(udc->lock, flags);
if (dir)
mEp = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
else
@@ -1556,11 +1577,12 @@
list_for_each(ptr, &mEp->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
-
- pr_info("\treq:%08x next:%08x token:%08x page0:%08x status:%d\n",
- req->dma, req->ptr->next, req->ptr->token,
- req->ptr->page[0], req->req.status);
+ list_for_each_entry(td, &req->td_list, list)
+ pr_info("\treq:%08x next:%08x token:%08x page0:%08x\n",
+ td->dma, td->ptr->next, td->ptr->token,
+ td->ptr->page[0]);
}
+ spin_unlock_irqrestore(udc->lock, flags);
done:
return count;
@@ -1740,6 +1762,7 @@
{
struct ci13xxx_ep *mep = (struct ci13xxx_ep *)data;
struct ci13xxx_req *req;
+ struct ci13xxx_td_wrapper *td;
struct list_head *ptr = NULL;
int n = hw_ep_bit(mep->num, mep->dir);
unsigned long flags;
@@ -1753,9 +1776,10 @@
goto out;
req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
+ td = list_first_entry(&req->td_list, struct ci13xxx_td_wrapper, list);
mb();
- if (!(TD_STATUS_ACTIVE & req->ptr->token))
+ if (!(TD_STATUS_ACTIVE & td->ptr->token))
goto out;
mep->prime_timer_count++;
@@ -1767,10 +1791,10 @@
mep->qh.ptr->td.next, mep->qh.ptr->td.token);
list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
- pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
- req->dma, req->ptr->next,
- req->ptr->token, req->ptr->page[0],
- req->req.status);
+ list_for_each_entry(td, &req->td_list, list)
+ pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08x\n",
+ td->dma, td->ptr->next,
+ td->ptr->token, td->ptr->page[0]);
}
dbg_usb_op_fail(0xFF, "PRIMEF", mep);
mep->prime_fail_count++;
@@ -1784,7 +1808,69 @@
out:
mep->prime_timer_count = 0;
spin_unlock_irqrestore(mep->lock, flags);
+}
+static int prepare_dtds(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ int i;
+ unsigned len;
+ unsigned remaining_len = mReq->req.length;
+ dma_addr_t dma = mReq->req.dma;
+ struct ci13xxx_td_wrapper *td = list_first_entry(&mReq->td_list,
+ struct ci13xxx_td_wrapper, list);
+ struct ci13xxx_td_wrapper *prev_td = NULL;
+ bool zlp = mReq->req.zero && remaining_len &&
+ (remaining_len % mEp->ep.maxpacket == 0);
+
+ do {
+ td = kmalloc(sizeof(*td), GFP_ATOMIC);
+ if (td == NULL) {
+ pr_err("td wrapper allocation failed\n");
+ goto free;
+ }
+ td->ptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+ &td->dma);
+ if (td->ptr == NULL) {
+ kfree(td);
+ pr_err("td allocation failed\n");
+ goto free;
+ }
+
+ list_add_tail(&td->list, &mReq->td_list);
+ if (zlp && !remaining_len)
+ zlp = false;
+
+ len = min_t(unsigned, remaining_len, CI13XXX_MAX_REQ_SIZE);
+ remaining_len -= len;
+ memset(td->ptr, 0, sizeof(*td->ptr));
+ td->ptr->token = len << ffs_nr(TD_TOTAL_BYTES);
+ td->ptr->token &= TD_TOTAL_BYTES;
+ td->ptr->token |= TD_STATUS_ACTIVE;
+
+ td->ptr->page[0] = dma;
+ for (i = 1; i < 5; i++)
+ td->ptr->page[i] = (dma + i * CI13XXX_PAGE_SIZE) &
+ ~TD_RESERVED_MASK;
+ if (prev_td)
+ prev_td->ptr->next = td->dma;
+
+ dma += len;
+ prev_td = td;
+
+ } while (remaining_len || zlp);
+
+ td->ptr->next = TD_TERMINATE;
+ if (!mReq->req.no_interrupt)
+ td->ptr->token |= TD_IOC;
+
+ return 0;
+free:
+ list_for_each_entry_safe(td, prev_td, &mReq->td_list, list) {
+ list_del(&td->list);
+ dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+ kfree(td);
+ }
+ return -ENOMEM;
}
/**
@@ -1799,7 +1885,7 @@
unsigned i;
int ret = 0;
unsigned length = mReq->req.length;
- struct ci13xxx *udc = _udc;
+ struct ci13xxx_td_wrapper *td;
trace("%p, %p", mEp, mReq);
@@ -1819,40 +1905,23 @@
mReq->map = 1;
}
- if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
- mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
- &mReq->zdma);
- if (mReq->zptr == NULL) {
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma,
- length, mEp->dir ? DMA_TO_DEVICE :
+ if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
+ mReq->req.dma = 0;
+
+ ret = prepare_dtds(mEp, mReq);
+ if (ret) {
+ pr_err("dTD preparation failed\n");
+ if (mReq->map) {
+ dma_unmap_single(mEp->device, mReq->req.dma,
+ mReq->req.length,
+ mEp->dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
- return -ENOMEM;
+ mReq->req.dma = DMA_ADDR_INVALID;
+ mReq->map = 0;
}
- memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = TD_TERMINATE;
- mReq->zptr->token = TD_STATUS_ACTIVE;
- if (!mReq->req.no_interrupt)
- mReq->zptr->token |= TD_IOC;
+ return ret;
}
- /*
- * TD configuration
- * TODO - handle requests which spawns into several TDs
- */
- memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
- mReq->ptr->token &= TD_TOTAL_BYTES;
- mReq->ptr->token |= TD_STATUS_ACTIVE;
- if (mReq->zptr) {
- mReq->ptr->next = mReq->zdma;
- } else {
- mReq->ptr->next = TD_TERMINATE;
- if (!mReq->req.no_interrupt)
- mReq->ptr->token |= TD_IOC;
- }
+ td = list_first_entry(&mReq->td_list, struct ci13xxx_td_wrapper, list);
/* MSM Specific: updating the request as required for
* SPS mode. Enable MSM proprietary DMA engine acording
@@ -1860,46 +1929,28 @@
*/
if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
if (mReq->req.udc_priv & MSM_SPS_MODE) {
- mReq->ptr->token = TD_STATUS_ACTIVE;
+ td->ptr->token = TD_STATUS_ACTIVE;
if (mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER)
- mReq->ptr->next = TD_TERMINATE;
+ td->ptr->next = TD_TERMINATE;
else
- mReq->ptr->next = MSM_ETD_TYPE | mReq->dma;
+ td->ptr->next = MSM_ETD_TYPE | td->dma;
if (!mReq->req.no_interrupt)
- mReq->ptr->token |= MSM_ETD_IOC;
+ td->ptr->token |= MSM_ETD_IOC;
}
- mReq->req.dma = 0;
- }
-
- mReq->ptr->page[0] = mReq->req.dma;
- for (i = 1; i < 5; i++)
- mReq->ptr->page[i] =
- (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
-
- /* Remote Wakeup */
- if (udc->suspended) {
- if (!udc->remote_wakeup) {
- mReq->req.status = -EAGAIN;
- dev_dbg(mEp->device, "%s: queue failed (suspend) ept #%d\n",
- __func__, mEp->num);
- return -EAGAIN;
- }
- usb_phy_set_suspend(udc->transceiver, 0);
- schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
}
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev;
+ struct ci13xxx_td_wrapper *prev_td;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
ktime_t start, diff;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
- if (mReqPrev->zptr)
- mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
- else
- mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ prev_td = list_entry(mReqPrev->td_list.prev,
+ struct ci13xxx_td_wrapper, list);
+ prev_td->ptr->next = td->dma & TD_ADDR_MASK;
wmb();
if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto done;
@@ -1928,15 +1979,17 @@
struct ci13xxx_req *mReq = \
list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
+ struct ci13xxx_td_wrapper *td = list_first_entry(&mReq->td_list,
+ struct ci13xxx_td_wrapper, list);
- if (TD_STATUS_ACTIVE & mReq->ptr->token) {
- mEp->qh.ptr->td.next = mReq->dma;
+ if (TD_STATUS_ACTIVE & td->ptr->token) {
+ mEp->qh.ptr->td.next = td->dma;
mEp->qh.ptr->td.token &= ~TD_STATUS;
goto prime;
}
}
- mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
+ mEp->qh.ptr->td.next = td->dma; /* TERMINATE = 0 */
if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
if (mReq->req.udc_priv & MSM_SPS_MODE) {
@@ -1993,27 +2046,27 @@
*/
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
+ struct ci13xxx_td_wrapper *td, *temp_td;
+ unsigned rem, total_rem = 0;
+ int status;
+
trace("%p, %p", mEp, mReq);
if (mReq->req.status != -EALREADY)
return -EINVAL;
- /* clean speculative fetches on req->ptr->token */
+ /* clean speculative fetches on td->ptr->token */
mb();
- if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+ td = list_entry(mReq->td_list.prev, struct ci13xxx_td_wrapper, list);
+
+ if ((TD_STATUS_ACTIVE & td->ptr->token) != 0)
return -EBUSY;
if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
if ((mReq->req.udc_priv & MSM_SPS_MODE) &&
(mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER))
return -EBUSY;
- if (mReq->zptr) {
- if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
- return -EBUSY;
- dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
- mReq->zptr = NULL;
- }
mReq->req.status = 0;
@@ -2024,18 +2077,27 @@
mReq->map = 0;
}
- mReq->req.status = mReq->ptr->token & TD_STATUS;
- if ((TD_STATUS_HALTED & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
+ list_for_each_entry_safe(td, temp_td, &mReq->td_list, list) {
- mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
- mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
- mReq->req.actual = mReq->req.length - mReq->req.actual;
- mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
+ status = td->ptr->token & TD_STATUS;
+ if ((status & TD_STATUS_HALTED) != 0)
+ mReq->req.status = -1;
+ else if ((status & TD_STATUS_DT_ERR) != 0)
+ mReq->req.status = -1;
+ else if ((status & TD_STATUS_TR_ERR) != 0)
+ mReq->req.status = -1;
+
+ rem = td->ptr->token & TD_TOTAL_BYTES;
+ rem >>= ffs_nr(TD_TOTAL_BYTES);
+ total_rem += rem;
+
+ list_del(&td->list);
+ dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+ kfree(td);
+ }
+
+ mReq->req.actual = mReq->req.status ? 0 :
+ (mReq->req.length - total_rem);
return mReq->req.actual;
}
@@ -2052,6 +2114,7 @@
__acquires(mEp->lock)
{
struct ci13xxx_ep *mEpTemp = mEp;
+ struct ci13xxx_td_wrapper *td, *temp_td;
unsigned val;
trace("%p", mEp);
@@ -2093,10 +2156,16 @@
mReq->map = 0;
}
+ list_for_each_entry_safe(td, temp_td, &mReq->td_list, list) {
+ list_del(&td->list);
+ dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+ kfree(td);
+ }
+
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
- mReq->req.length)
+ mReq->req.length)
mEpTemp = &_udc->ep0in;
mReq->req.complete(&mEpTemp->ep, &mReq->req);
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
@@ -2191,6 +2260,7 @@
if (retval)
goto done;
+ _udc->skip_flush = false;
retval = hw_usb_reset();
if (retval)
goto done;
@@ -2442,7 +2512,7 @@
}
req_dequeue = 0;
list_del_init(&mReq->queue);
- dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+ dbg_done(_usb_addr(mEp), &mReq->req);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -2810,18 +2880,14 @@
}
mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
- if (mReq != NULL) {
- INIT_LIST_HEAD(&mReq->queue);
- mReq->req.dma = DMA_ADDR_INVALID;
+ if (mReq == NULL)
+ goto out;
- mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
- &mReq->dma);
- if (mReq->ptr == NULL) {
- kfree(mReq);
- mReq = NULL;
- }
- }
+ INIT_LIST_HEAD(&mReq->queue);
+ mReq->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&mReq->td_list);
+out:
dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
return (mReq == NULL) ? NULL : &mReq->req;
@@ -2850,8 +2916,6 @@
spin_lock_irqsave(mEp->lock, flags);
- if (mReq->ptr)
- dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
kfree(mReq);
dbg_event(_usb_addr(mEp), "FREE", 0);
@@ -2889,6 +2953,17 @@
return -ESHUTDOWN;
}
+ if (udc->suspended) {
+ if (!udc->remote_wakeup) {
+ mReq->req.status = -EAGAIN;
+ dev_dbg(mEp->device, "%s: queue failed (suspend) ept #%d\n",
+ __func__, mEp->num);
+ return -EAGAIN;
+ }
+ usb_phy_set_suspend(udc->transceiver, 0);
+ schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
+ }
+
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
if (req->length)
mEp = (_udc->ep0_dir == RX) ?
@@ -2907,11 +2982,9 @@
goto done;
}
- if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
- req->length = (4 * CI13XXX_PAGE_SIZE);
- retval = -EMSGSIZE;
- warn("request length truncated");
- }
+ /* REMOVE ME */
+ if (req->length > (CI13XXX_MAX_REQ_SIZE))
+ pr_warn_once("bigger request length\n");
dbg_queue(_usb_addr(mEp), req, retval);
@@ -2943,6 +3016,7 @@
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_ep *mEpTemp = mEp;
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx_td_wrapper *td, *temp_td;
unsigned long flags;
trace("%p, %p", ep, req);
@@ -2973,6 +3047,12 @@
}
req->status = -ECONNRESET;
+ list_for_each_entry_safe(td, temp_td, &mReq->td_list, list) {
+ list_del(&td->list);
+ dma_pool_free(mEp->td_pool, td->ptr, td->dma);
+ kfree(td);
+ }
+
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -3502,8 +3582,7 @@
void __iomem *regs)
{
struct ci13xxx *udc;
- struct ci13xxx_platform_data *pdata =
- (struct ci13xxx_platform_data *)(dev->platform_data);
+ struct ci13xxx_platform_data *pdata;
int retval = 0, i;
trace("%p, %p, %p", dev, regs, driver->name);
@@ -3532,6 +3611,7 @@
INIT_LIST_HEAD(&udc->gadget.ep_list);
udc->gadget.ep0 = NULL;
+ pdata = dev->platform_data;
if (pdata)
udc->gadget.usb_core_id = pdata->usb_core_id;
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 6b3cad8..f3351af 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -20,6 +20,7 @@
* DEFINE
*****************************************************************************/
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
+#define CI13XXX_MAX_REQ_SIZE (4 * CI13XXX_PAGE_SIZE)
#define ENDPT_MAX (32)
#define CTRL_PAYLOAD_MAX (64)
#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
@@ -77,15 +78,18 @@
struct usb_ctrlrequest setup;
} __attribute__ ((packed));
+struct ci13xxx_td_wrapper {
+ struct ci13xxx_td *ptr;
+ dma_addr_t dma;
+ struct list_head list;
+};
+
/* Extension of usb_request */
struct ci13xxx_req {
struct usb_request req;
unsigned map;
struct list_head queue;
- struct ci13xxx_td *ptr;
- dma_addr_t dma;
- struct ci13xxx_td *zptr;
- dma_addr_t zdma;
+ struct list_head td_list;
};
/* Extension of usb_ep */
@@ -162,6 +166,9 @@
int softconnect; /* is pull-up enable allowed */
unsigned long dTD_update_fail_count;
struct usb_phy *transceiver; /* Transceiver struct */
+ bool skip_flush; /* skip flushing remaining EP
+ upon flush timeout for the
+ first EP. */
};
struct ci13xxx_platform_data {
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
index aae941e..f0d5c52 100644
--- a/drivers/usb/gadget/f_audio_source.c
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -256,6 +256,8 @@
ktime_t start_time;
/* number of frames sent since start_time */
s64 frames_sent;
+
+ bool audio_ep_enabled;
};
static inline struct audio_dev *func_to_audio_source(struct usb_function *f)
@@ -525,18 +527,26 @@
pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt);
- ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
- if (ret) {
- audio->in_ep->desc = NULL;
- ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
- audio->in_ep->name, ret);
- return ret;
- }
- ret = usb_ep_enable(audio->in_ep);
- if (ret) {
- ERROR(cdev, "failed to enable ep %s, result %d\n",
- audio->in_ep->name, ret);
- return ret;
+ if (intf == as_interface_alt_1_desc.bInterfaceNumber) {
+ if (alt && !audio->audio_ep_enabled) {
+ ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
+ if (ret) {
+ audio->in_ep->desc = NULL;
+ ERROR(cdev, "config_ep fail ep %s, result %d\n",
+ audio->in_ep->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(audio->in_ep);
+ if (ret) {
+ ERROR(cdev, "failedto enable ep%s, result %d\n",
+ audio->in_ep->name, ret);
+ return ret;
+ }
+ audio->audio_ep_enabled = true;
+ } else if (!alt && audio->audio_ep_enabled) {
+ usb_ep_disable(audio->in_ep);
+ audio->audio_ep_enabled = false;
+ }
}
return 0;
}
@@ -546,7 +556,10 @@
struct audio_dev *audio = func_to_audio_source(f);
pr_debug("audio_disable\n");
- usb_ep_disable(audio->in_ep);
+ if (audio->audio_ep_enabled) {
+ usb_ep_disable(audio->in_ep);
+ audio->audio_ep_enabled = false;
+ }
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index a95bf24..3b1843b 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -2,7 +2,7 @@
* Diag Function Device - Route ARM9 and ARM11 DIAG messages
* between HOST and DEVICE.
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2013, Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -158,14 +158,19 @@
unsigned configured;
struct usb_composite_dev *cdev;
int (*update_pid_and_serial_num)(uint32_t, const char *);
- struct usb_diag_ch ch;
+ struct usb_diag_ch *ch;
/* pkt counters */
unsigned long dpkts_tolaptop;
unsigned long dpkts_tomodem;
unsigned dpkts_tolaptop_pending;
+
+ /* A list node inside the diag_dev_list */
+ struct list_head list_item;
};
+static struct list_head diag_dev_list;
+
static inline struct diag_context *func_to_diag(struct usb_function *f)
{
return container_of(f, struct diag_context, function);
@@ -179,8 +184,11 @@
struct usb_gadget_strings *table;
struct usb_string *s;
- if (ctxt->ch.notify)
- ctxt->ch.notify(ctxt->ch.priv, USB_DIAG_CONNECT, NULL);
+ if (!ctxt->ch)
+ return;
+
+ if (ctxt->ch->notify)
+ ctxt->ch->notify(ctxt->ch->priv, USB_DIAG_CONNECT, NULL);
if (!ctxt->update_pid_and_serial_num)
return;
@@ -236,8 +244,8 @@
}
spin_unlock_irqrestore(&ctxt->lock, flags);
- if (ctxt->ch.notify)
- ctxt->ch.notify(ctxt->ch.priv, USB_DIAG_WRITE_DONE, d_req);
+ if (ctxt->ch && ctxt->ch->notify)
+ ctxt->ch->notify(ctxt->ch->priv, USB_DIAG_WRITE_DONE, d_req);
}
static void diag_read_complete(struct usb_ep *ep,
@@ -256,8 +264,8 @@
ctxt->dpkts_tomodem++;
- if (ctxt->ch.notify)
- ctxt->ch.notify(ctxt->ch.priv, USB_DIAG_READ_DONE, d_req);
+ if (ctxt->ch && ctxt->ch->notify)
+ ctxt->ch->notify(ctxt->ch->priv, USB_DIAG_READ_DONE, d_req);
}
/**
@@ -275,7 +283,6 @@
void (*notify)(void *, unsigned, struct diag_request *))
{
struct usb_diag_ch *ch;
- struct diag_context *ctxt;
unsigned long flags;
int found = 0;
@@ -290,11 +297,9 @@
spin_unlock_irqrestore(&ch_lock, flags);
if (!found) {
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
- if (!ctxt)
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (!ch)
return ERR_PTR(-ENOMEM);
-
- ch = &ctxt->ch;
}
ch->name = name;
@@ -318,17 +323,18 @@
*/
void usb_diag_close(struct usb_diag_ch *ch)
{
- struct diag_context *dev = container_of(ch, struct diag_context, ch);
+ struct diag_context *dev = NULL;
unsigned long flags;
spin_lock_irqsave(&ch_lock, flags);
ch->priv = NULL;
ch->notify = NULL;
/* Free-up the resources if channel is no more active */
- if (!ch->priv_usb) {
- list_del(&ch->list);
- kfree(dev);
- }
+ list_del(&ch->list);
+ list_for_each_entry(dev, &diag_dev_list, list_item)
+ if (dev->ch == ch)
+ dev->ch = NULL;
+ kfree(ch);
spin_unlock_irqrestore(&ch_lock, flags);
}
@@ -555,15 +561,16 @@
dev->configured = 0;
spin_unlock_irqrestore(&dev->lock, flags);
- if (dev->ch.notify)
- dev->ch.notify(dev->ch.priv, USB_DIAG_DISCONNECT, NULL);
+ if (dev->ch && dev->ch->notify)
+ dev->ch->notify(dev->ch->priv, USB_DIAG_DISCONNECT, NULL);
usb_ep_disable(dev->in);
dev->in->driver_data = NULL;
usb_ep_disable(dev->out);
dev->out->driver_data = NULL;
-
+ if (dev->ch)
+ dev->ch->priv_usb = NULL;
}
static int diag_function_set_alt(struct usb_function *f,
@@ -581,6 +588,15 @@
return -EINVAL;
}
+ if (!dev->ch)
+ return -ENODEV;
+
+ /*
+ * Indicate to the diag channel that the active diag device is dev.
+ * Since a few diag devices can point to the same channel.
+ */
+ dev->ch->priv_usb = dev;
+
dev->in->driver_data = dev;
rc = usb_ep_enable(dev->in);
if (rc) {
@@ -620,7 +636,16 @@
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
- ctxt->ch.priv_usb = NULL;
+
+ /*
+ * Channel priv_usb may point to other diag function.
+ * Clear the priv_usb only if the channel is used by the
+ * diag dev we unbind here.
+ */
+ if (ctxt->ch && ctxt->ch->priv_usb == ctxt)
+ ctxt->ch->priv_usb = NULL;
+ list_del(&ctxt->list_item);
+ kfree(ctxt);
}
static int diag_function_bind(struct usb_configuration *c,
@@ -710,9 +735,19 @@
return -ENODEV;
}
- dev = container_of(_ch, struct diag_context, ch);
- /* claim the channel for this USB interface */
- _ch->priv_usb = dev;
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ list_add_tail(&dev->list_item, &diag_dev_list);
+
+ /*
+ * A few diag devices can point to the same channel, in case that
+ * the diag devices belong to different configurations, however
+ * only the active diag device will claim the channel by setting
+ * the ch->priv_usb (see diag_function_set_alt).
+ */
+ dev->ch = _ch;
dev->update_pid_and_serial_num = update_pid;
dev->cdev = c->cdev;
@@ -731,13 +766,13 @@
ret = usb_add_function(c, &dev->function);
if (ret) {
INFO(c->cdev, "usb_add_function failed\n");
- _ch->priv_usb = NULL;
+ list_del(&dev->list_item);
+ kfree(dev);
}
return ret;
}
-
#if defined(CONFIG_DEBUG_FS)
static char debug_buffer[PAGE_SIZE];
@@ -815,7 +850,6 @@
static void diag_cleanup(void)
{
- struct diag_context *dev;
struct list_head *act, *tmp;
struct usb_diag_ch *_ch;
unsigned long flags;
@@ -824,13 +858,12 @@
list_for_each_safe(act, tmp, &usb_diag_ch_list) {
_ch = list_entry(act, struct usb_diag_ch, list);
- dev = container_of(_ch, struct diag_context, ch);
spin_lock_irqsave(&ch_lock, flags);
/* Free if diagchar is not using the channel anymore */
if (!_ch->priv) {
list_del(&_ch->list);
- kfree(dev);
+ kfree(_ch);
}
spin_unlock_irqrestore(&ch_lock, flags);
}
@@ -838,6 +871,8 @@
static int diag_setup(void)
{
+ INIT_LIST_HEAD(&diag_dev_list);
+
fdiag_debugfs_init();
return 0;
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 82ffbba..0c0d58a 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -67,6 +67,9 @@
#define MTP_RESPONSE_OK 0x2001
#define MTP_RESPONSE_DEVICE_BUSY 0x2019
+unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR);
+
static const char mtp_shortname[] = "mtp_usb";
struct mtp_dev {
@@ -493,10 +496,27 @@
req->complete = mtp_complete_in;
mtp_req_put(dev, &dev->tx_idle, req);
}
+
+ /*
+ * The RX buffer should be aligned to EP max packet for
+ * some controllers. At bind time, we don't know the
+ * operational speed. Hence assuming super speed max
+ * packet size.
+ */
+ if (mtp_rx_req_len % 1024)
+ mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+
+retry_rx_alloc:
for (i = 0; i < RX_REQ_MAX; i++) {
- req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE);
- if (!req)
- goto fail;
+ req = mtp_request_new(dev->ep_out, mtp_rx_req_len);
+ if (!req) {
+ if (mtp_rx_req_len <= MTP_BULK_BUFFER_SIZE)
+ goto fail;
+ for (; i > 0; i--)
+ mtp_request_free(dev->rx_req[i], dev->ep_out);
+ mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
+ goto retry_rx_alloc;
+ }
req->complete = mtp_complete_out;
dev->rx_req[i] = req;
}
@@ -526,7 +546,7 @@
DBG(cdev, "mtp_read(%d)\n", count);
- if (count > MTP_BULK_BUFFER_SIZE)
+ if (count > mtp_rx_req_len)
return -EINVAL;
if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
@@ -554,7 +574,7 @@
requeue_req:
/* queue a request */
req = dev->rx_req[0];
- req->length = MTP_BULK_BUFFER_SIZE;
+ req->length = mtp_rx_req_len;
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
if (ret < 0) {
@@ -832,7 +852,7 @@
cur_buf = (cur_buf + 1) % RX_REQ_MAX;
/* some h/w expects size to be aligned to ep's MTU */
- read_req->length = MTP_BULK_BUFFER_SIZE;
+ read_req->length = mtp_rx_req_len;
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 887a10c..e35a60e 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1259,6 +1259,9 @@
struct msm_request *req, *next_req = NULL;
unsigned long flags;
+ if (!ept->req)
+ return;
+
/* inactive endpoints have nothing to do here */
if (ept->ep.maxpacket == 0)
return;
@@ -1303,9 +1306,13 @@
static irqreturn_t usb_interrupt(int irq, void *data)
{
struct usb_info *ui = data;
+ struct msm_otg *dev = to_msm_otg(ui->xceiv);
unsigned n;
unsigned long flags;
+ if (atomic_read(&dev->in_lpm))
+ return IRQ_NONE;
+
n = readl(USB_USBSTS);
writel(n, USB_USBSTS);
@@ -2202,6 +2209,9 @@
struct msm_endpoint *ep = to_msm_endpoint(_ep);
struct usb_info *ui = ep->ui;
+ if (!atomic_read(&ui->softconnect))
+ return -ENODEV;
+
if (ep == &ui->ep0in) {
struct msm_request *r = to_msm_request(req);
if (!req->length)
@@ -2229,6 +2239,13 @@
struct msm_request *temp_req;
unsigned long flags;
+ if (ep->num == 0) {
+ /* Flush both out and in control endpoints */
+ flush_endpoint(&ui->ep0out);
+ flush_endpoint(&ui->ep0in);
+ return 0;
+ }
+
if (!(ui && req && ep->req))
return -EINVAL;
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 746c041..575d85b 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -634,10 +634,10 @@
ghsic_data_free_buffers(port);
- data_bridge_close(port->brdg.ch_id);
-
+ cancel_work_sync(&port->connect_w);
+ if (test_and_clear_bit(CH_OPENED, &port->bridge_sts))
+ data_bridge_close(port->brdg.ch_id);
clear_bit(CH_READY, &port->bridge_sts);
- clear_bit(CH_OPENED, &port->bridge_sts);
return 0;
}
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 028d5e6..2931ace 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -15,8 +15,6 @@
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
-#define BAM_CONNC_IDX 0 /* USB bam connection index */
-
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@@ -57,17 +55,18 @@
pr_err("send_sps_req: usb_ep_queue error\n");
return -EIO;
}
+
return 0;
}
int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
{
int res = 0;
-
+ u8 conn_num = usb_bam_get_qdss_num();
pr_debug("set_qdss_data_connection\n");
if (enable) {
- res = usb_bam_connect(BAM_CONNC_IDX, NULL,
+ res = usb_bam_connect(conn_num, NULL,
&(bam_info.usb_bam_pipe_idx));
if (res) {
pr_err("usb_bam_connection error\n");
@@ -80,7 +79,7 @@
pr_err("qdss_data_connection: memory alloc failed\n");
return -ENOMEM;
}
- get_bam2bam_connection_info(BAM_CONNC_IDX,
+ get_bam2bam_connection_info(conn_num,
PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
@@ -89,7 +88,7 @@
bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
- res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
+ res = usb_bam_disconnect_pipe(conn_num);
if (res) {
pr_err("usb_bam_disconnection error\n");
return res;
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 169008b..5817779 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -32,6 +32,8 @@
#define SMD_CH_MAX_LEN 20
#define CH_OPENED 0
#define CH_READY 1
+#define CH_PREPARE_READY 2
+
struct smd_ch_info {
struct smd_channel *ch;
char *name;
@@ -60,6 +62,7 @@
spinlock_t port_lock;
struct delayed_work connect_w;
+ struct delayed_work disconnect_w;
};
static struct rmnet_ctrl_ports {
@@ -324,6 +327,7 @@
{
struct rmnet_ctrl_port *port =
container_of(w, struct rmnet_ctrl_port, connect_w.work);
+ struct rmnet_ctrl_ports *port_entry = &ctrl_smd_ports[port->port_num];
struct smd_ch_info *c = &port->ctrl_ch;
unsigned long flags;
int set_bits = 0;
@@ -332,8 +336,13 @@
pr_debug("%s:\n", __func__);
- if (!test_bit(CH_READY, &c->flags))
+ if (!test_bit(CH_READY, &c->flags)) {
+ if (!test_bit(CH_PREPARE_READY, &c->flags)) {
+ set_bit(CH_PREPARE_READY, &c->flags);
+ platform_driver_register(&(port_entry->pdrv));
+ }
return;
+ }
ret = smd_open(c->name, &c->ch, port, grmnet_ctrl_smd_notify);
if (ret) {
@@ -390,6 +399,23 @@
return 0;
}
+static void grmnet_ctrl_smd_disconnect_w(struct work_struct *w)
+{
+ struct rmnet_ctrl_port *port =
+ container_of(w, struct rmnet_ctrl_port,
+ disconnect_w.work);
+ struct smd_ch_info *c;
+ struct platform_driver *pdrv;
+
+ c = &port->ctrl_ch;
+ if (test_bit(CH_READY, &c->flags) ||
+ test_bit(CH_PREPARE_READY, &c->flags)) {
+ clear_bit(CH_PREPARE_READY, &c->flags);
+ pdrv = &ctrl_smd_ports[port->port_num].pdrv;
+ platform_driver_unregister(pdrv);
+ }
+}
+
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num)
{
struct rmnet_ctrl_port *port;
@@ -435,6 +461,8 @@
smd_close(c->ch);
c->ch = NULL;
}
+
+ queue_delayed_work(grmnet_ctrl_wq, &port->disconnect_w, 0);
}
#define SMD_CH_MAX_LEN 20
@@ -452,6 +480,7 @@
c = &port->ctrl_ch;
if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
+ clear_bit(CH_PREPARE_READY, &c->flags);
set_bit(CH_READY, &c->flags);
/* if usb is online, try opening smd_ch */
@@ -520,6 +549,7 @@
spin_lock_init(&port->port_lock);
INIT_DELAYED_WORK(&port->connect_w, grmnet_ctrl_smd_connect_w);
+ INIT_DELAYED_WORK(&port->disconnect_w, grmnet_ctrl_smd_disconnect_w);
c = &port->ctrl_ch;
c->name = rmnet_ctrl_names[portno];
@@ -537,8 +567,6 @@
pdrv->driver.name = c->name;
pdrv->driver.owner = THIS_MODULE;
- platform_driver_register(pdrv);
-
pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
return 0;
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 34d90fb..5c87691 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1,6 +1,6 @@
/* ehci-msm2.c - HSUSB Host Controller Driver Implementation
*
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
*
* Partly derived from ehci-fsl.c and ehci-hcd.c
* Copyright (c) 2000-2004 by David Brownell
@@ -32,6 +32,7 @@
#include <linux/usb/ulpi.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/msm_hsusb.h>
+#include <linux/of.h>
#include <mach/clk.h>
#include <mach/msm_xo.h>
#include <mach/msm_iomap.h>
@@ -42,10 +43,12 @@
struct msm_hcd {
struct ehci_hcd ehci;
+ spinlock_t wakeup_lock;
struct device *dev;
struct clk *iface_clk;
struct clk *core_clk;
struct clk *alt_core_clk;
+ struct clk *phy_sleep_clk;
struct regulator *hsusb_vddcx;
struct regulator *hsusb_3p3;
struct regulator *hsusb_1p8;
@@ -60,6 +63,9 @@
atomic_t pm_usage_cnt;
struct wake_lock wlock;
struct work_struct phy_susp_fail_work;
+ int async_irq;
+ bool async_irq_enabled;
+ uint32_t async_int_cnt;
};
static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -272,6 +278,7 @@
int rc = 0;
struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
const struct msm_usb_host_platform_data *pdata;
+ int ret = 0;
pdata = mhcd->dev->platform_data;
@@ -282,7 +289,11 @@
}
mhcd->vbus = devm_regulator_get(mhcd->dev, "vbus");
- if (IS_ERR(mhcd->vbus)) {
+ ret = PTR_ERR(mhcd->vbus);
+ if (ret == -EPROBE_DEFER) {
+ pr_debug("failed to get vbus handle, defer probe\n");
+ return ret;
+ } else if (IS_ERR(mhcd->vbus)) {
pr_err("Unable to get vbus\n");
return -ENODEV;
}
@@ -435,18 +446,38 @@
return 0;
}
+/**
+ * Do hard reset to USB hardware block using one of reset methodology based
+ * on availablity of alt_core_clk. There are two kinds of hardware resets.
+ * 1. Conventional synchronous reset where clocks to blocks to be ON while
+ * issuing the reset. 2. Asynchronous reset which requires clocks to be OFF.
+ */
static int msm_ehci_link_clk_reset(struct msm_hcd *mhcd, bool assert)
{
int ret;
if (assert) {
- ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+ if (!IS_ERR(mhcd->alt_core_clk)) {
+ ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+ } else {
+ /* Using asynchronous block reset to the hardware */
+ clk_disable(mhcd->iface_clk);
+ clk_disable(mhcd->core_clk);
+ ret = clk_reset(mhcd->core_clk, CLK_RESET_ASSERT);
+ }
if (ret)
- dev_err(mhcd->dev, "usb alt_core_clk assert failed\n");
+ dev_err(mhcd->dev, "usb clk assert failed\n");
} else {
- ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+ if (!IS_ERR(mhcd->alt_core_clk)) {
+ ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+ } else {
+ ret = clk_reset(mhcd->core_clk, CLK_RESET_DEASSERT);
+ ndelay(200);
+ clk_enable(mhcd->core_clk);
+ clk_enable(mhcd->iface_clk);
+ }
if (ret)
- dev_err(mhcd->dev, "usb alt_core_clk deassert failed\n");
+ dev_err(mhcd->dev, "usb clk deassert failed\n");
}
return ret;
@@ -455,6 +486,7 @@
static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
{
struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ struct msm_usb_host_platform_data *pdata;
u32 val;
int ret;
int retries;
@@ -463,12 +495,17 @@
if (ret)
return ret;
- udelay(1);
+ usleep_range(10, 12);
ret = msm_ehci_link_clk_reset(mhcd, 0);
if (ret)
return ret;
+ pdata = mhcd->dev->platform_data;
+ if (pdata && pdata->use_sec_phy)
+ /* select secondary phy if offset is set for USB operation */
+ writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+ USB_PHY_CTRL2);
val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
@@ -499,10 +536,13 @@
static int msm_hsusb_reset(struct msm_hcd *mhcd)
{
struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ struct msm_usb_host_platform_data *pdata;
unsigned long timeout;
int ret;
- clk_prepare_enable(mhcd->alt_core_clk);
+ if (!IS_ERR(mhcd->alt_core_clk))
+ clk_prepare_enable(mhcd->alt_core_clk);
+
ret = msm_ehci_phy_reset(mhcd);
if (ret) {
dev_err(mhcd->dev, "phy_reset failed\n");
@@ -521,6 +561,11 @@
/* select ULPI phy */
writel_relaxed(0x80000000, USB_PORTSC);
+ pdata = mhcd->dev->platform_data;
+ if (pdata && pdata->use_sec_phy)
+ writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+ USB_PHY_CTRL2);
+
msleep(100);
writel_relaxed(0x0, USB_AHBBURST);
@@ -528,7 +573,9 @@
/* Ensure that RESET operation is completed before turning off clock */
mb();
- clk_disable_unprepare(mhcd->alt_core_clk);
+
+ if (!IS_ERR(mhcd->alt_core_clk))
+ clk_disable_unprepare(mhcd->alt_core_clk);
/*rising edge interrupts with Dp rise and fall enabled*/
msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_RISE);
@@ -626,6 +673,11 @@
enable_irq_wake(mhcd->pmic_gpio_dp_irq);
enable_irq(mhcd->pmic_gpio_dp_irq);
}
+ if (mhcd->async_irq) {
+ mhcd->async_irq_enabled = 1;
+ enable_irq_wake(mhcd->async_irq);
+ enable_irq(mhcd->async_irq);
+ }
wake_unlock(&mhcd->wlock);
dev_info(mhcd->dev, "EHCI USB in low power mode\n");
@@ -639,6 +691,7 @@
unsigned long timeout;
unsigned temp;
int ret;
+ unsigned long flags;
if (!atomic_read(&mhcd->in_lpm)) {
dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
@@ -650,6 +703,14 @@
disable_irq_nosync(mhcd->pmic_gpio_dp_irq);
mhcd->pmic_gpio_dp_irq_enabled = 0;
}
+ spin_lock_irqsave(&mhcd->wakeup_lock, flags);
+ if (mhcd->async_irq_enabled) {
+ disable_irq_wake(mhcd->async_irq);
+ disable_irq_nosync(mhcd->async_irq);
+ mhcd->async_irq_enabled = 0;
+ }
+ spin_unlock_irqrestore(&mhcd->wakeup_lock, flags);
+
wake_lock(&mhcd->wlock);
/* Vote for TCXO when waking up the phy */
@@ -722,6 +783,36 @@
return ehci_irq(hcd);
}
+static irqreturn_t msm_async_irq(int irq, void *data)
+{
+ struct msm_hcd *mhcd = data;
+ int ret;
+
+ mhcd->async_int_cnt++;
+ dev_dbg(mhcd->dev, "%s: hsusb host remote wakeup interrupt cnt: %u\n",
+ __func__, mhcd->async_int_cnt);
+
+ wake_lock(&mhcd->wlock);
+
+ spin_lock(&mhcd->wakeup_lock);
+ if (mhcd->async_irq_enabled) {
+ mhcd->async_irq_enabled = 0;
+ disable_irq_wake(irq);
+ disable_irq_nosync(irq);
+ }
+ spin_unlock(&mhcd->wakeup_lock);
+
+ if (!atomic_read(&mhcd->pm_usage_cnt)) {
+ ret = pm_runtime_get(mhcd->dev);
+ if ((ret == 1) || (ret == -EINPROGRESS))
+ pm_runtime_put_noidle(mhcd->dev);
+ else
+ atomic_set(&mhcd->pm_usage_cnt, 1);
+ }
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t msm_ehci_host_wakeup_irq(int irq, void *data)
{
@@ -751,6 +842,8 @@
static int msm_ehci_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+ struct msm_usb_host_platform_data *pdata;
int retval;
ehci->caps = USB_CAPLENGTH;
@@ -785,6 +878,11 @@
/* Disable streaming mode and select host mode */
writel_relaxed(0x13, USB_USBMODE);
+ pdata = mhcd->dev->platform_data;
+ if (pdata && pdata->use_sec_phy)
+ writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+ USB_PHY_CTRL2);
+
ehci_port_power(ehci, 1);
return 0;
}
@@ -844,12 +942,10 @@
/* 60MHz alt_core_clk is for LINK to be used during PHY RESET */
mhcd->alt_core_clk = clk_get(mhcd->dev, "alt_core_clk");
- if (IS_ERR(mhcd->alt_core_clk)) {
- dev_err(mhcd->dev, "failed to get alt_core_clk\n");
- ret = PTR_ERR(mhcd->alt_core_clk);
- return ret;
- }
- clk_set_rate(mhcd->alt_core_clk, 60000000);
+ if (IS_ERR(mhcd->alt_core_clk))
+ dev_dbg(mhcd->dev, "failed to get alt_core_clk\n");
+ else
+ clk_set_rate(mhcd->alt_core_clk, 60000000);
/* iface_clk is required for data transfers */
mhcd->iface_clk = clk_get(mhcd->dev, "iface_clk");
@@ -871,6 +967,12 @@
}
clk_set_rate(mhcd->core_clk, INT_MAX);
+ mhcd->phy_sleep_clk = clk_get(mhcd->dev, "sleep_clk");
+ if (IS_ERR(mhcd->phy_sleep_clk))
+ dev_dbg(mhcd->dev, "failed to get sleep_clk\n");
+ else
+ clk_prepare_enable(mhcd->phy_sleep_clk);
+
clk_prepare_enable(mhcd->core_clk);
clk_prepare_enable(mhcd->iface_clk);
@@ -880,14 +982,39 @@
clk_disable_unprepare(mhcd->iface_clk);
clk_disable_unprepare(mhcd->core_clk);
clk_put(mhcd->core_clk);
+ if (!IS_ERR(mhcd->phy_sleep_clk)) {
+ clk_disable_unprepare(mhcd->phy_sleep_clk);
+ clk_put(mhcd->phy_sleep_clk);
+ }
put_iface_clk:
clk_put(mhcd->iface_clk);
put_alt_core_clk:
- clk_put(mhcd->alt_core_clk);
+ if (!IS_ERR(mhcd->alt_core_clk))
+ clk_put(mhcd->alt_core_clk);
return ret;
}
+struct msm_usb_host_platform_data *ehci_msm2_dt_to_pdata(
+ struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_usb_host_platform_data *pdata;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "unable to allocate platform data\n");
+ return NULL;
+ }
+
+ pdata->use_sec_phy = of_property_read_bool(node,
+ "qcom,usb2-enable-hsphy2");
+ of_property_read_u32(node, "qcom,usb2-power-budget",
+ &pdata->power_budget);
+ return pdata;
+}
+
+static u64 ehci_msm_dma_mask = DMA_BIT_MASK(64);
static int __devinit ehci_msm2_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -899,6 +1026,19 @@
dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "device tree enabled\n");
+ pdev->dev.platform_data = ehci_msm2_dt_to_pdata(pdev);
+ }
+
+ if (!pdev->dev.platform_data)
+ dev_dbg(&pdev->dev, "No platform data given\n");
+
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &ehci_msm_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
hcd = usb_create_hcd(&msm_hc2_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {
@@ -932,13 +1072,29 @@
mhcd = hcd_to_mhcd(hcd);
mhcd->dev = &pdev->dev;
+ spin_lock_init(&mhcd->wakeup_lock);
+
+ mhcd->async_irq = platform_get_irq_byname(pdev, "async_irq");
+ if (mhcd->async_irq < 0) {
+ dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
+ mhcd->async_irq = 0;
+ } else {
+ ret = request_irq(mhcd->async_irq, msm_async_irq,
+ IRQF_TRIGGER_RISING, "msm_ehci_host", mhcd);
+ if (ret) {
+ dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+ goto unmap;
+ }
+ disable_irq(mhcd->async_irq);
+ }
+
snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id);
mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
if (IS_ERR(mhcd->xo_handle)) {
dev_err(&pdev->dev, "%s not able to get the handle "
"to vote for TCXO D0 buffer\n", __func__);
ret = PTR_ERR(mhcd->xo_handle);
- goto unmap;
+ goto free_async_irq;
}
ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
@@ -1047,6 +1203,9 @@
msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
free_xo_handle:
msm_xo_put(mhcd->xo_handle);
+free_async_irq:
+ if (mhcd->async_irq)
+ free_irq(mhcd->async_irq, mhcd);
unmap:
iounmap(hcd->regs);
put_hcd:
@@ -1065,6 +1224,11 @@
disable_irq_wake(mhcd->pmic_gpio_dp_irq);
free_irq(mhcd->pmic_gpio_dp_irq, mhcd);
}
+ if (mhcd->async_irq) {
+ if (mhcd->async_irq_enabled)
+ disable_irq_wake(mhcd->async_irq);
+ free_irq(mhcd->async_irq, mhcd);
+ }
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
@@ -1160,6 +1324,12 @@
};
#endif
+static const struct of_device_id ehci_msm2_dt_match[] = {
+ { .compatible = "qcom,ehci-host",
+ },
+ {}
+};
+
static struct platform_driver ehci_msm2_driver = {
.probe = ehci_msm2_probe,
.remove = __devexit_p(ehci_msm2_remove),
@@ -1168,5 +1338,6 @@
#ifdef CONFIG_PM
.pm = &ehci_msm2_dev_pm_ops,
#endif
+ .of_match_table = ehci_msm2_dt_match,
},
};
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index e55fed7..79dcf2f 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -122,6 +122,7 @@
if (!hcd)
return -ENOMEM;
+ hcd_to_bus(hcd)->skip_resume = true;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
@@ -153,6 +154,7 @@
goto dealloc_usb2_hcd;
}
+ hcd_to_bus(xhci->shared_hcd)->skip_resume = true;
/*
* Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
* is called by usb_add_hcd().
@@ -173,6 +175,8 @@
usb_put_transceiver(phy);
goto put_usb3_hcd;
}
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
} else {
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
@@ -205,6 +209,7 @@
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
@@ -225,11 +230,74 @@
return 0;
}
+#ifdef CONFIG_PM_RUNTIME
+static int xhci_msm_runtime_idle(struct device *dev)
+{
+ dev_dbg(dev, "xhci msm runtime idle\n");
+ return 0;
+}
+
+static int xhci_msm_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "xhci msm runtime suspend\n");
+ /*
+ * Notify OTG about suspend. It takes care of
+ * putting the hardware in LPM.
+ */
+ if (phy)
+ return usb_phy_set_suspend(phy, 1);
+
+ return 0;
+}
+
+static int xhci_msm_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "xhci msm runtime resume\n");
+
+ if (phy)
+ return usb_phy_set_suspend(phy, 0);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int xhci_msm_pm_suspend(struct device *dev)
+{
+ dev_dbg(dev, "xhci-msm PM suspend\n");
+
+ if (phy)
+ return usb_phy_set_suspend(phy, 1);
+
+ return 0;
+}
+
+static int xhci_msm_pm_resume(struct device *dev)
+{
+ dev_dbg(dev, "xhci-msm PM resume\n");
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ if (phy)
+ return usb_phy_set_suspend(phy, 0);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops xhci_msm_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(xhci_msm_pm_suspend, xhci_msm_pm_resume)
+ SET_RUNTIME_PM_OPS(xhci_msm_runtime_suspend, xhci_msm_runtime_resume,
+ xhci_msm_runtime_idle)
+};
+
static struct platform_driver usb_xhci_driver = {
.probe = xhci_plat_probe,
.remove = xhci_plat_remove,
.driver = {
.name = "xhci-hcd",
+ .pm = &xhci_msm_dev_pm_ops,
},
};
MODULE_ALIAS("platform:xhci-hcd");
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index e76a9a8..5a3dfa3 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -510,31 +510,32 @@
struct urb *urb;
int i = 0;
int ret;
+ bool put = true;
+ ret = usb_autopm_get_interface(ksb->ifc);
+ if (ret < 0) {
+ if (ret != -EAGAIN && ret != -EACCES) {
+ pr_err_ratelimited("autopm_get failed:%d", ret);
+ return;
+ }
+ put = false;
+ }
for (i = 0; i < NO_RX_REQS; i++) {
if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
- return;
+ break;
pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
if (IS_ERR(pkt)) {
pr_err("unable to allocate data pkt");
- return;
+ break;
}
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
pr_err("unable to allocate urb");
ksb_free_data_pkt(pkt);
- return;
- }
-
- ret = usb_autopm_get_interface(ksb->ifc);
- if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
- pr_err_ratelimited("autopm_get failed:%d", ret);
- usb_free_urb(urb);
- ksb_free_data_pkt(pkt);
- return;
+ break;
}
usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
@@ -551,15 +552,15 @@
usb_unanchor_urb(urb);
usb_free_urb(urb);
ksb_free_data_pkt(pkt);
- usb_autopm_put_interface(ksb->ifc);
atomic_dec(&ksb->rx_pending_cnt);
wake_up(&ksb->pending_urb_wait);
- return;
+ break;
}
- usb_autopm_put_interface_async(ksb->ifc);
usb_free_urb(urb);
}
+ if (put)
+ usb_autopm_put_interface_async(ksb->ifc);
}
static int
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 655e2f6..fcbf0e1 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -343,6 +343,9 @@
dev_dbg(&dev->intf->dev, "%s:\n", __func__);
+ cancel_work_sync(&dev->kevent);
+ cancel_work_sync(&dev->process_rx_w);
+
usb_unlink_anchored_urbs(&dev->tx_active);
usb_unlink_anchored_urbs(&dev->rx_active);
usb_unlink_anchored_urbs(&dev->delayed);
@@ -995,9 +998,6 @@
usb_set_intfdata(intf, NULL);
__dev[dev->id] = NULL;
- cancel_work_sync(&dev->process_rx_w);
- cancel_work_sync(&dev->kevent);
-
/*free rx urbs*/
head = &dev->rx_idle;
spin_lock_irqsave(&dev->rx_done.lock, flags);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 6530ed6..dae7f79 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -485,9 +485,13 @@
ret = msm_otg_phy_clk_reset(motg);
if (ret)
return ret;
- /* 10 usec delay is required according to spec */
+
+ /*
+ * 10 usec delay is required according to spec. Using larger value
+ * since the exact value proved to not work 100% of the time.
+ */
if (IS_ERR(motg->phy_reset_clk))
- usleep_range(10, 12);
+ usleep_range(100, 120);
ret = msm_otg_link_clk_reset(motg, 0);
if (ret)
return ret;
@@ -2484,6 +2488,7 @@
pr_debug("chg_work cancel");
del_timer_sync(&motg->chg_check_timer);
clear_bit(B_FALSE_SDP, &motg->inputs);
+ clear_bit(A_BUS_REQ, &motg->inputs);
cancel_delayed_work_sync(&motg->chg_work);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 0411baa..a3b92ed 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -829,6 +829,74 @@
return ret;
}
+static ssize_t hdmi_common_rda_audio_data_block(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int adb_size = 0;
+ int adb_count = 0;
+ ssize_t ret = 0;
+ char *data = buf;
+
+ if (!external_common_state)
+ return 0;
+
+ adb_count = 1;
+ adb_size = external_common_state->adb_size;
+ ret = sizeof(adb_count) + sizeof(adb_size) + adb_size;
+
+ if (ret > PAGE_SIZE) {
+ DEV_DBG("%s: Insufficient buffer size\n", __func__);
+ return 0;
+ }
+
+ /* Currently only extracting one audio data block */
+ memcpy(data, &adb_count, sizeof(adb_count));
+ data += sizeof(adb_count);
+ memcpy(data, &adb_size, sizeof(adb_size));
+ data += sizeof(adb_size);
+ memcpy(data, external_common_state->audio_data_block,
+ external_common_state->adb_size);
+
+ print_hex_dump(KERN_DEBUG, "AUDIO DATA BLOCK: ", DUMP_PREFIX_NONE,
+ 32, 8, buf, ret, false);
+
+ return ret;
+}
+
+static ssize_t hdmi_common_rda_spkr_alloc_data_block(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int sadb_size = 0;
+ int sadb_count = 0;
+ ssize_t ret = 0;
+ char *data = buf;
+
+ if (!external_common_state)
+ return 0;
+
+ sadb_count = 1;
+ sadb_size = external_common_state->sadb_size;
+ ret = sizeof(sadb_count) + sizeof(sadb_size) + sadb_size;
+
+ if (ret > PAGE_SIZE) {
+ DEV_DBG("%s: Insufficient buffer size\n", __func__);
+ return 0;
+ }
+
+ /* Currently only extracting one speaker allocation data block */
+ memcpy(data, &sadb_count, sizeof(sadb_count));
+ data += sizeof(sadb_count);
+ memcpy(data, &sadb_size, sizeof(sadb_size));
+ data += sizeof(sadb_size);
+ memcpy(data, external_common_state->spkr_alloc_data_block,
+ external_common_state->sadb_size);
+
+ print_hex_dump(KERN_DEBUG, "SPKR ALLOC DATA BLOCK: ", DUMP_PREFIX_NONE,
+ 32, 8, buf, ret, false);
+
+ return ret;
+}
+
static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO,
external_common_rda_video_mode, external_common_wta_video_mode);
static DEVICE_ATTR(video_mode_str, S_IRUGO, external_common_rda_video_mode_str,
@@ -859,6 +927,10 @@
hdmi_3d_wta_format_3d);
#endif
static DEVICE_ATTR(hdmi_primary, S_IRUGO, hdmi_common_rda_hdmi_primary, NULL);
+static DEVICE_ATTR(audio_data_block, S_IRUGO, hdmi_common_rda_audio_data_block,
+ NULL);
+static DEVICE_ATTR(spkr_alloc_data_block, S_IRUGO,
+ hdmi_common_rda_spkr_alloc_data_block, NULL);
static struct attribute *external_common_fs_attrs[] = {
&dev_attr_video_mode.attr,
@@ -887,6 +959,8 @@
&dev_attr_cec_wr_frame.attr,
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */
&dev_attr_hdmi_primary.attr,
+ &dev_attr_audio_data_block.attr,
+ &dev_attr_spkr_alloc_data_block.attr,
NULL,
};
static struct attribute_group external_common_fs_attr_group = {
@@ -1205,45 +1279,33 @@
static void hdmi_edid_extract_speaker_allocation_data(const uint8 *in_buf)
{
uint8 len;
- const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4,
+ const uint8 *sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4,
&len);
- if (sad == NULL)
+ if (sadb == NULL)
return;
- external_common_state->speaker_allocation_block = sad[1];
- DEV_DBG("EDID: speaker allocation data SP byte = %08x %s%s%s%s%s%s%s\n",
- sad[1],
- (sad[1] & BIT(0)) ? "FL/FR," : "",
- (sad[1] & BIT(1)) ? "LFE," : "",
- (sad[1] & BIT(2)) ? "FC," : "",
- (sad[1] & BIT(3)) ? "RL/RR," : "",
- (sad[1] & BIT(4)) ? "RC," : "",
- (sad[1] & BIT(5)) ? "FLC/FRC," : "",
- (sad[1] & BIT(6)) ? "RLC/RRC," : "");
+ if (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)
+ return;
+
+ memcpy(external_common_state->spkr_alloc_data_block, sadb + 1, len);
+ external_common_state->sadb_size = len;
}
static void hdmi_edid_extract_audio_data_blocks(const uint8 *in_buf)
{
uint8 len;
- const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1,
+ const uint8 *adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1,
&len);
- uint32 *adb = external_common_state->audio_data_blocks;
- if (sad == NULL)
+ if (external_common_state->audio_data_block == NULL)
return;
- external_common_state->audio_data_block_cnt = 0;
- while (len >= 3 && external_common_state->audio_data_block_cnt < 16) {
- DEV_DBG("EDID: Audio Data Block=<ch=%d, format=%d "
- "sampling=0x%02x bit-depth=0x%02x>\n",
- (sad[1] & 0x7)+1, sad[1] >> 3, sad[2], sad[3]);
- *adb++ = (uint32)sad[1] + ((uint32)sad[2] << 8)
- + ((uint32)sad[2] << 16);
- ++external_common_state->audio_data_block_cnt;
- len -= 3;
- sad += 3;
- }
+ if (len > MAX_AUDIO_DATA_BLOCK_SIZE)
+ return;
+
+ memcpy(external_common_state->audio_data_block, adb + 1, len);
+ external_common_state->adb_size = len;
}
static void hdmi_edid_extract_extended_data_blocks(const uint8 *in_buf)
@@ -1874,6 +1936,12 @@
sizeof(external_common_state->disp_mode_list));
memset(edid_buf, 0, sizeof(edid_buf));
external_common_state->default_res_supported = false;
+ memset(external_common_state->audio_data_block, 0,
+ sizeof(external_common_state->audio_data_block));
+ memset(external_common_state->spkr_alloc_data_block, 0,
+ sizeof(external_common_state->spkr_alloc_data_block));
+ external_common_state->adb_size = 0;
+ external_common_state->sadb_size = 0;
status = hdmi_common_read_edid_block(0, edid_buf);
if (status || !check_edid_header(edid_buf)) {
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index 70a99ee..b27e4c8 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -206,6 +206,14 @@
};
#endif
+/*
+ * As per the CEA-861E spec, there can be a total of 10 short audio
+ * descriptors with each SAD being 3 bytes long.
+ * Thus, the maximum length of the audio data block would be 30 bytes
+ */
+#define MAX_AUDIO_DATA_BLOCK_SIZE 30
+#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3
+
struct external_common_state_type {
boolean hpd_state;
struct kobject *uevent_kobj;
@@ -223,9 +231,7 @@
boolean hpd_feature_on;
boolean hdmi_sink;
struct hdmi_disp_mode_list_type disp_mode_list;
- uint8 speaker_allocation_block;
uint16 video_latency, audio_latency;
- uint8 audio_data_block_cnt;
uint16 physical_address;
uint32 preferred_video_format;
uint8 pt_scan_info;
@@ -235,7 +241,10 @@
uint8 spd_product_description[16];
boolean present_3d;
boolean present_hdcp;
- uint32 audio_data_blocks[16];
+ uint8 audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE];
+ int adb_size;
+ uint8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
+ int sadb_size;
int (*read_edid_block)(int block, uint8 *edid_buf);
int (*hpd_feature)(int on);
#endif
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 38fc969..2423de5 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -3087,14 +3087,11 @@
int ret = 0;
unsigned int ptr;
- if (addr == NULL)
- goto end;
-
ptr = (unsigned int) addr;
if (mdp_rev >= MDP_REV_30 && mdp_rev < MDP_REV_40) {
/* if request is outside the MDP reg-map or is not aligned 4 */
- if (ptr > 0xF0600 || ptr % 0x4)
+ if (ptr == 0x0 || ptr > 0xF0600 || ptr % 0x4)
goto end;
if (ptr >= 0x90000 && ptr < 0x94000) {
@@ -3119,7 +3116,8 @@
goto end;
if (ptr < 0x90000) {
- if (ptr == 0x4 || ptr == 0x28200 || ptr == 0x28204)
+ if (ptr == 0x0 || ptr == 0x4 || ptr == 0x28200 ||
+ ptr == 0x28204)
ret = 1;
} else if (ptr < 0x95000) {
if (ptr == 0x90000 || ptr == 0x90070)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 80db0b2..a283e0a 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -588,10 +588,10 @@
msleep(20);
ret = mfd->off_fnc(mfd);
- if (ret) {
+ if (ret)
mfd->panel_power_on = curr_pwr_state;
+ else
mdss_fb_release_fences(mfd);
- }
mfd->op_enable = true;
}
break;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index ef6e5b4..40cca22 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -308,6 +308,7 @@
int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
struct mdp_csc_cfg *data);
+int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 2f4c2ed..6030cbc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -698,6 +698,14 @@
ctl->power_on = false;
ctl->play_cnt = 0;
ctl->clk_rate = 0;
+ if (ctl->mixer_left) {
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(
+ ctl->mixer_left->num), 0);
+ }
+ if (ctl->mixer_right) {
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(
+ ctl->mixer_right->num), 0);
+ }
mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index a7f0148..d2b2eab 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -185,6 +185,7 @@
#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY 0x224
#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX 0x228
#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY 0x22C
+#define MDSS_MDP_REG_VIG_PA_BASE 0x310
#define MDSS_MDP_REG_SCALE_CONFIG 0x204
#define MDSS_MDP_REG_SCALE_PHASE_STEP_X 0x210
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index a1f1bcc..2c0ddda 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -265,6 +265,9 @@
ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
if (ctx) {
+ mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
+ NULL, NULL);
+
ctl->priv_data = NULL;
ctx->ref_cnt--;
}
@@ -318,8 +321,6 @@
flush_bits = BIT(16); /* WB */
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
- mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
- mdss_mdp_writeback_intr_done, ctx);
mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
@@ -353,6 +354,9 @@
ctx->wb_num = ctl->num; /* wb num should match ctl num */
ctx->initialized = false;
+ mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
+ mdss_mdp_writeback_intr_done, ctx);
+
if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
ctl->prepare_fnc = mdss_mdp_writeback_prepare_rot;
else /* wfd or line mode */
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 338cf87..3956228 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -263,11 +263,11 @@
pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
if (pipe && pipe->ndx != req->id) {
- pr_err("stage %d taken by pnum=%d\n", req->z_order, pipe->num);
- return -EBUSY;
+ pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
+ pipe->num, req->z_order, mixer_mux);
+ pipe->params_changed = true;
}
-
if (req->id == MSMFB_NEW_REQUEST) {
mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
if (!mixer) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 89f3405..4ece15d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -584,43 +584,6 @@
return 0;
}
-static int mdss_mdp_vig_setup(struct mdss_mdp_pipe *pipe)
-{
- u32 opmode = 0;
-
- pr_debug("pnum=%x\n", pipe->num);
-
- /* CSC Post Processing enabled? */
- if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
- if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG) {
- if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_ENABLE)
- opmode |= 1 << 17; /* CSC_1_EN */
- if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_IN)
- opmode |= 1 << 18; /* SRC_DATA=YCBCR */
- if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_OUT)
- opmode |= 1 << 19; /* DST_DATA=YCBCR */
- /* only need to program once */
- if (pipe->play_cnt == 0)
- mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
- pipe->num, 1, &pipe->pp_cfg.csc_cfg);
- }
- } else {
- if (pipe->src_fmt->is_yuv)
- opmode |= (0 << 19) | /* DST_DATA=RGB */
- (1 << 18) | /* SRC_DATA=YCBCR */
- (1 << 17); /* CSC_1_EN */
- /* only need to program once */
- if (pipe->play_cnt == 0) {
- mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
- MDSS_MDP_CSC_YUV2RGB);
- }
- }
-
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
-
- return 0;
-}
-
static void mdss_mdp_addr_add_offset(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_data *data)
{
@@ -678,7 +641,7 @@
struct mdss_mdp_data *src_data)
{
int ret = 0;
- u32 params_changed;
+ u32 params_changed, opmode;
if (!pipe) {
pr_err("pipe not setup properly for queue\n");
@@ -712,8 +675,10 @@
goto done;
}
+ mdss_mdp_pipe_pp_setup(pipe, &opmode);
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
- mdss_mdp_vig_setup(pipe);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE,
+ opmode);
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 7fd6a58..242be60 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -159,7 +159,7 @@
struct mdp_ar_gc_lut_data
gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
- struct mdp_pa_cfg_data pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_pa_cfg pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_pgc_lut_data argc_disp_cfg[MDSS_BLOCK_DISP_NUM];
@@ -181,19 +181,29 @@
static DEFINE_MUTEX(mdss_mdp_hist_mutex);
static struct mdss_pp_res_type *mdss_pp_res;
-
static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info);
-
static void pp_update_pcc_regs(u32 offset,
struct mdp_pcc_cfg_data *cfg_ptr);
static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
u32 offset, u32 blk_idx);
static void pp_update_gc_one_lut(u32 offset,
- struct mdp_ar_gc_lut_data *lut_data);
+ struct mdp_ar_gc_lut_data *lut_data);
static void pp_update_argc_lut(u32 offset,
- struct mdp_pgc_lut_data *config);
+ struct mdp_pgc_lut_data *config);
static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg);
-
+static void pp_pa_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_pa_cfg *pa_config);
+static void pp_pcc_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_pcc_cfg_data *pcc_config);
+static void pp_igc_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_igc_lut_data *igc_config,
+ u32 pipe_num);
+static void pp_enhist_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_hist_lut_data *enhist_cfg);
int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
struct mdp_csc_cfg *data)
@@ -283,6 +293,192 @@
data = &mdp_csc_convert[csc_type];
return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
}
+
+static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
+ u32 base, u32 *gamut_sts)
+{
+ u32 offset;
+ int i, j;
+ if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
+ offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+ MDSS_MDP_REG_WRITE(offset,
+ (u32)gamut_cfg->r_tbl[i][j]);
+ offset += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+ MDSS_MDP_REG_WRITE(offset,
+ (u32)gamut_cfg->g_tbl[i][j]);
+ offset += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+ MDSS_MDP_REG_WRITE(offset,
+ (u32)gamut_cfg->b_tbl[i][j]);
+ offset += 4;
+ }
+ if (gamut_cfg->gamut_first)
+ *gamut_sts |= PP_STS_GAMUT_FIRST;
+ }
+
+ if (gamut_cfg->flags & MDP_PP_OPS_DISABLE)
+ *gamut_sts &= ~PP_STS_ENABLE;
+ else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
+ *gamut_sts |= PP_STS_ENABLE;
+}
+
+static void pp_pa_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_pa_cfg *pa_config)
+{
+ if (flags & PP_FLAGS_DIRTY_PA) {
+ if (pa_config->flags & MDP_PP_OPS_WRITE) {
+ MDSS_MDP_REG_WRITE(base, pa_config->hue_adj);
+ base += 4;
+ MDSS_MDP_REG_WRITE(base, pa_config->sat_adj);
+ base += 4;
+ MDSS_MDP_REG_WRITE(base, pa_config->val_adj);
+ base += 4;
+ MDSS_MDP_REG_WRITE(base, pa_config->cont_adj);
+ }
+ if (pa_config->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->pa_sts &= ~PP_STS_ENABLE;
+ else if (pa_config->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->pa_sts |= PP_STS_ENABLE;
+ }
+}
+
+static void pp_pcc_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_pcc_cfg_data *pcc_config)
+{
+ if (flags & PP_FLAGS_DIRTY_PCC) {
+ if (pcc_config->ops & MDP_PP_OPS_WRITE)
+ pp_update_pcc_regs(base, pcc_config);
+
+ if (pcc_config->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->pcc_sts &= ~PP_STS_ENABLE;
+ else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->pcc_sts |= PP_STS_ENABLE;
+ }
+}
+
+static void pp_igc_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_igc_lut_data *igc_config,
+ u32 pipe_num)
+{
+ u32 tbl_idx;
+ if (flags & PP_FLAGS_DIRTY_IGC) {
+ if (igc_config->ops & MDP_PP_OPS_WRITE)
+ pp_update_igc_lut(igc_config, base, pipe_num);
+
+ if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
+ pp_sts->pcc_sts |= PP_STS_ENABLE;
+ tbl_idx = 1;
+ } else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
+ pp_sts->pcc_sts |= PP_STS_ENABLE;
+ tbl_idx = 2;
+ } else {
+ tbl_idx = 0;
+ }
+ pp_sts->igc_tbl_idx = tbl_idx;
+ if (igc_config->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->igc_sts &= ~PP_STS_ENABLE;
+ else if (igc_config->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->igc_sts |= PP_STS_ENABLE;
+ }
+}
+
+static void pp_enhist_config(unsigned long flags, u32 base,
+ struct pp_sts_type *pp_sts,
+ struct mdp_hist_lut_data *enhist_cfg)
+{
+ if (flags & PP_FLAGS_DIRTY_ENHIST) {
+ if (enhist_cfg->ops & MDP_PP_OPS_WRITE)
+ pp_update_hist_lut(base, enhist_cfg);
+
+ if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->enhist_sts &= ~PP_STS_ENABLE;
+ else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->enhist_sts |= PP_STS_ENABLE;
+ }
+}
+
+static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
+{
+ struct pp_sts_type pp_sts;
+ u32 opmode = 0, base = 0;
+ unsigned long flags = 0;
+
+ pr_debug("pnum=%x\n", pipe->num);
+
+ if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) &&
+ (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) {
+ opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
+ MDP_CSC_FLAG_ENABLE) << 17;
+ opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
+ MDP_CSC_FLAG_YUV_IN) << 18;
+ opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
+ MDP_CSC_FLAG_YUV_OUT) << 19;
+ /*
+ * TODO: Allow pipe to be programmed whenever new CSC is
+ * applied (i.e. dirty bit)
+ */
+ if (pipe->play_cnt == 0)
+ mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
+ pipe->num, 1, &pipe->pp_cfg.csc_cfg);
+ } else {
+ if (pipe->src_fmt->is_yuv)
+ opmode |= (0 << 19) | /* DST_DATA=RGB */
+ (1 << 18) | /* SRC_DATA=YCBCR */
+ (1 << 17); /* CSC_1_EN */
+ /*
+ * TODO: Needs to be part of dirty bit logic: if there is a
+ * previously configured pipe need to re-configure CSC matrix
+ */
+ if (pipe->play_cnt == 0) {
+ mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
+ MDSS_MDP_CSC_YUV2RGB);
+ }
+ }
+
+ if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
+ if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) {
+ flags = PP_FLAGS_DIRTY_PA;
+ base = MDSS_MDP_REG_SSPP_OFFSET(pipe->num) +
+ MDSS_MDP_REG_VIG_PA_BASE;
+ pp_sts.pa_sts = 0;
+ pp_pa_config(flags, base, &pp_sts,
+ &pipe->pp_cfg.pa_cfg);
+ if (pp_sts.pa_sts & PP_STS_ENABLE)
+ opmode |= (1 << 4); /* PA_EN */
+ }
+ }
+
+ *op = opmode;
+
+ return 0;
+}
+
+int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op)
+{
+ int ret = 0;
+ if (!pipe)
+ return -ENODEV;
+
+ if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
+ ret = pp_vig_pipe_setup(pipe, op);
+ else if (pipe->type == MDSS_MDP_PIPE_TYPE_RGB)
+ ret = -EINVAL;
+ else if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
+ ret = -EINVAL;
+
+ return ret;
+}
+
static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
struct mdss_mdp_mixer *mixer)
{
@@ -326,65 +522,16 @@
}
return 0;
}
-static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
- u32 base,
- u32 *gamut_sts)
-{
- u32 offset;
- int i, j;
- if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
- for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
- for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
- MDSS_MDP_REG_WRITE(offset,
- (u32)gamut_cfg->r_tbl[i][j]);
- offset += 4;
- }
- for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
- for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
- MDSS_MDP_REG_WRITE(offset,
- (u32)gamut_cfg->g_tbl[i][j]);
- offset += 4;
- }
- for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
- for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
- MDSS_MDP_REG_WRITE(offset,
- (u32)gamut_cfg->b_tbl[i][j]);
- offset += 4;
- }
- if (gamut_cfg->gamut_first)
- *gamut_sts |= PP_STS_GAMUT_FIRST;
- }
-
- if (gamut_cfg->flags & MDP_PP_OPS_DISABLE)
- *gamut_sts &= ~PP_STS_ENABLE;
- else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
- *gamut_sts |= PP_STS_ENABLE;
-}
-
-/* Note: Assumes that its inputs have been checked by calling function */
-static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg)
-{
- int i;
- for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
- MDSS_MDP_REG_WRITE(offset, cfg->data[i]);
- /* swap */
- MDSS_MDP_REG_WRITE(offset + 4, 1);
-}
static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
- struct mdss_mdp_mixer *mixer)
+ struct mdss_mdp_mixer *mixer)
{
u32 flags, base, offset, dspp_num, opmode = 0;
- struct mdp_pa_cfg_data *pa_config;
- struct mdp_pcc_cfg_data *pcc_config;
- struct mdp_igc_lut_data *igc_config;
- struct mdp_hist_lut_data *enhist_cfg;
struct mdp_dither_cfg_data *dither_cfg;
struct pp_hist_col_info *hist_info;
struct mdp_pgc_lut_data *pgc_config;
struct pp_sts_type *pp_sts;
- u32 data, tbl_idx, col_state;
+ u32 data, col_state;
unsigned long flag;
int i;
@@ -423,76 +570,32 @@
/* nothing to update */
if ((!flags) && (!(hist_info->col_en)))
return 0;
+
pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
- if (flags & PP_FLAGS_DIRTY_PA) {
- pa_config = &mdss_pp_res->pa_disp_cfg[disp_num];
- if (pa_config->pa_data.flags & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
- MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.hue_adj);
- offset += 4;
- MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.sat_adj);
- offset += 4;
- MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.val_adj);
- offset += 4;
- MDSS_MDP_REG_WRITE(offset, pa_config->pa_data.cont_adj);
- }
- if (pa_config->pa_data.flags & MDP_PP_OPS_DISABLE)
- pp_sts->pa_sts &= ~PP_STS_ENABLE;
- else if (pa_config->pa_data.flags & MDP_PP_OPS_ENABLE)
- pp_sts->pa_sts |= PP_STS_ENABLE;
- }
+
+ pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
+ &mdss_pp_res->pa_disp_cfg[disp_num]);
+
+ pp_pcc_config(flags, base + MDSS_MDP_REG_DSPP_PCC_BASE, pp_sts,
+ &mdss_pp_res->pcc_disp_cfg[disp_num]);
+
+ pp_igc_config(flags, MDSS_MDP_REG_IGC_DSPP_BASE, pp_sts,
+ &mdss_pp_res->igc_disp_cfg[disp_num], dspp_num);
+
+ pp_enhist_config(flags, base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+ pp_sts, &mdss_pp_res->enhist_disp_cfg[disp_num]);
+
if (pp_sts->pa_sts & PP_STS_ENABLE)
opmode |= (1 << 20); /* PA_EN */
- if (flags & PP_FLAGS_DIRTY_PCC) {
- pcc_config = &mdss_pp_res->pcc_disp_cfg[disp_num];
- if (pcc_config->ops & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_PCC_BASE;
- pp_update_pcc_regs(offset, pcc_config);
- }
- if (pcc_config->ops & MDP_PP_OPS_DISABLE)
- pp_sts->pcc_sts &= ~PP_STS_ENABLE;
- else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
- pp_sts->pcc_sts |= PP_STS_ENABLE;
- }
+
if (pp_sts->pcc_sts & PP_STS_ENABLE)
opmode |= (1 << 4); /* PCC_EN */
- if (flags & PP_FLAGS_DIRTY_IGC) {
- igc_config = &mdss_pp_res->igc_disp_cfg[disp_num];
- if (igc_config->ops & MDP_PP_OPS_WRITE) {
- offset = MDSS_MDP_REG_IGC_DSPP_BASE;
- pp_update_igc_lut(igc_config, offset, dspp_num);
- }
- if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
- pp_sts->pcc_sts |= PP_STS_ENABLE;
- tbl_idx = 1;
- } else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
- pp_sts->pcc_sts |= PP_STS_ENABLE;
- tbl_idx = 2;
- } else {
- tbl_idx = 0;
- }
- pp_sts->igc_tbl_idx = tbl_idx;
- if (igc_config->ops & MDP_PP_OPS_DISABLE)
- pp_sts->igc_sts &= ~PP_STS_ENABLE;
- else if (igc_config->ops & MDP_PP_OPS_ENABLE)
- pp_sts->igc_sts |= PP_STS_ENABLE;
- }
if (pp_sts->igc_sts & PP_STS_ENABLE) {
opmode |= (1 << 0) | /* IGC_LUT_EN */
(pp_sts->igc_tbl_idx << 1);
}
- if (flags & PP_FLAGS_DIRTY_ENHIST) {
- enhist_cfg = &mdss_pp_res->enhist_disp_cfg[disp_num];
- if (enhist_cfg->ops & MDP_PP_OPS_WRITE) {
- offset = base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
- pp_update_hist_lut(offset, enhist_cfg);
- }
- if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
- pp_sts->enhist_sts &= ~PP_STS_ENABLE;
- else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
- pp_sts->enhist_sts |= PP_STS_ENABLE;
- }
+
if (pp_sts->enhist_sts & PP_STS_ENABLE) {
opmode |= (1 << 19) | /* HIST_LUT_EN */
(1 << 20); /* PA_EN */
@@ -557,6 +660,7 @@
ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
return 0;
}
+
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
{
u32 disp_num;
@@ -676,7 +780,7 @@
*copyback = 1;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
} else {
- mdss_pp_res->pa_disp_cfg[disp_num] = *config;
+ mdss_pp_res->pa_disp_cfg[disp_num] = config->pa_data;
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA;
}
@@ -1056,6 +1160,17 @@
pp_read_gc_one_lut(offset, config->b_data);
return ret;
}
+
+/* Note: Assumes that its inputs have been checked by calling function */
+static void pp_update_hist_lut(u32 offset, struct mdp_hist_lut_data *cfg)
+{
+ int i;
+ for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+ MDSS_MDP_REG_WRITE(offset, cfg->data[i]);
+ /* swap */
+ MDSS_MDP_REG_WRITE(offset + 4, 1);
+}
+
int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
{
int ret = 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 75a926a..911e29f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -78,7 +78,7 @@
void (*fnc_ptr)(void *), void *arg)
{
unsigned long flags;
- int index, ret;
+ int index;
index = mdss_mdp_intr2index(intr_type, intf_num);
if (index < 0) {
@@ -88,16 +88,13 @@
}
spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
- if (!mdp_intr_cb[index].func) {
- mdp_intr_cb[index].func = fnc_ptr;
- mdp_intr_cb[index].arg = arg;
- ret = 0;
- } else {
- ret = -EBUSY;
- }
+ WARN(mdp_intr_cb[index].func && fnc_ptr,
+ "replacing current intr callback for ndx=%d\n", index);
+ mdp_intr_cb[index].func = fnc_ptr;
+ mdp_intr_cb[index].arg = arg;
spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);
- return ret;
+ return 0;
}
static inline void mdss_mdp_intr_done(int index)
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 460cba3..2cea256 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -5,7 +5,7 @@
* & Ralph Metzler <ralph@convergence.de>
* for convergence integrated media GmbH
*
- * Copyright (c) 2012, Code Aurora Forum. 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 Lesser General Public License
@@ -39,8 +39,7 @@
/* Min recording chunk upon which event is generated */
#define DMX_REC_BUFF_CHUNK_MIN_SIZE (100*188)
-/* Decoder buffers are usually large ~1MB, 10 should suffice */
-#define DMX_MAX_DECODER_BUFFER_NUM (10)
+#define DMX_MAX_DECODER_BUFFER_NUM (32)
typedef enum
{
@@ -250,6 +249,18 @@
/* Flags passed in filter events */
__u32 flags;
+
+ /*
+ * Number of TS packets with Transport Error Indicator (TEI)
+ * found while constructing the PES.
+ */
+ __u32 transport_error_indicator_counter;
+
+ /* Number of continuity errors found while constructing the PES */
+ __u32 continuity_error_counter;
+
+ /* Total number of TS packets holding the PES */
+ __u32 ts_packets_num;
};
/* Section info associated with DMX_EVENT_NEW_SECTION event */
@@ -562,6 +573,20 @@
int handles[DMX_MAX_DECODER_BUFFER_NUM];
};
+struct dmx_secure_mode {
+ /*
+ * Specifies whether secure mode should be set or not for the filter's
+ * pid. Note that DMX_OUT_TSDEMUX_TAP filters can have more than 1 pid
+ */
+ int is_secured;
+
+ /* PID to associate with key ladder id */
+ __u16 pid;
+
+ /* key ladder information to associate with the specified pid */
+ __u32 key_ladder_id;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -585,5 +610,7 @@
#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer)
#define DMX_SET_DECODER_BUFFER _IOW('o', 63, struct dmx_decoder_buffers)
#define DMX_REUSE_DECODER_BUFFER _IO('o', 64)
+#define DMX_SET_SECURE_MODE _IOW('o', 65, struct dmx_secure_mode)
+
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index fe23993..b903dfb 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
- * Copyright (c) 2011-2012, Code Aurora Forum. 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 as published by the
@@ -32,8 +32,10 @@
/* Bootoader IDs */
#define MXT_BOOTLOADER_ID_224 0x0A
#define MXT_BOOTLOADER_ID_224E 0x06
+#define MXT_BOOTLOADER_ID_336S 0x1A
#define MXT_BOOTLOADER_ID_1386 0x01
#define MXT_BOOTLOADER_ID_1386E 0x10
+#define MXT_BOOTLOADER_ID_1664S 0x14
/* Config data for a given maXTouch controller with a specific firmware */
struct mxt_config_info {
@@ -75,6 +77,7 @@
int *key_codes;
bool need_calibration;
bool no_force_update;
+ u8 bl_addr;
u8(*read_chg) (void);
int (*init_hw) (bool);
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/include/linux/input/gen_vkeys.h
similarity index 65%
copy from arch/arm/boot/dts/msm8974-mtp.dts
copy to include/linux/input/gen_vkeys.h
index 9946cf0..ce29351 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/include/linux/input/gen_vkeys.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
@@ -10,13 +10,14 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-
-/include/ "msm8974.dtsi"
-/include/ "msm8974-mtp.dtsi"
-
-/ {
- model = "Qualcomm MSM 8974 MTP";
- compatible = "qcom,msm8974-mtp", "qcom,msm8974";
- qcom,msm-id = <126 8 0>;
+#ifndef __GEN_VKEYS_
+struct vkeys_platform_data {
+ const char *name;
+ int disp_maxx;
+ int disp_maxy;
+ int panel_maxx;
+ int panel_maxy;
+ int *keycodes;
+ int num_keys;
};
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 8ab3ac2..28b210b 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -41,6 +41,9 @@
* voltage higher than cutoff voltage
* @low_voltage_calc_ms: The period of soc calculation in ms when battery
* voltage is near cutoff voltage
+ * @disable_flat_portion_ocv: feature to disable ocv updates while in sleep
+ * @ocv_dis_high_soc: the high soc percent when ocv should be disabled
+ * @ocv_dis_low_soc: the low soc percent when ocv should be enabled
*/
struct pm8921_bms_platform_data {
struct pm8xxx_bms_core_data bms_cdata;
@@ -57,6 +60,9 @@
int chg_term_ua;
int normal_voltage_calc_ms;
int low_voltage_calc_ms;
+ int disable_flat_portion_ocv;
+ int ocv_dis_high_soc;
+ int ocv_dis_low_soc;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/test-iosched.h b/include/linux/test-iosched.h
index ec28463..3690160 100644
--- a/include/linux/test-iosched.h
+++ b/include/linux/test-iosched.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. 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
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 9240277..c588420 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -412,6 +412,7 @@
unsigned int power_budget;
int pmic_gpio_dp_irq;
unsigned int dock_connect_irq;
+ bool use_sec_phy;
};
/**
@@ -473,6 +474,7 @@
* @active_conn_num: number of active pipe connections.
* @usb_base_address: BAM physical address.
* @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
+ * @disable_clk_gating: Disable clock gating
*/
struct msm_usb_bam_platform_data {
struct usb_bam_pipe_connect *connections;
@@ -482,6 +484,7 @@
u32 usb_base_address;
bool ignore_core_reset_ack;
bool reset_on_connect[MAX_BAMS];
+ bool disable_clk_gating;
};
/**
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 6e36f56..900fc00 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -28,6 +28,7 @@
#define USB_OTGSC (MSM_USB_BASE + 0x01A4)
#define USB_USBMODE (MSM_USB_BASE + 0x01A8)
#define USB_PHY_CTRL (MSM_USB_BASE + 0x0240)
+#define USB_PHY_CTRL2 (MSM_USB_BASE + 0x0278)
#define USBCMD_RESET 2
#define USB_USBINTR (MSM_USB_BASE + 0x0148)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index bc25e24..9d38db32 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1498,6 +1498,7 @@
V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0,
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1,
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_GOB = 3,
};
#define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222)
#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223)
@@ -1845,7 +1846,8 @@
V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE = 0,
V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO = 1,
};
-
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+27)
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index ab76d79..993a4ab 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -1,8 +1,8 @@
#ifndef __MEDIA_INFO_H__
#define __MEDIA_INFO_H__
-#ifndef ALIGN
-#define ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1)))
+#ifndef MSM_MEDIA_ALIGN
+#define MSM_MEDIA_ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1)))
#endif
enum color_fmts {
@@ -18,7 +18,7 @@
switch (color_fmt) {
case COLOR_FMT_NV12:
alignment = 128;
- stride = ALIGN(width, alignment);
+ stride = MSM_MEDIA_ALIGN(width, alignment);
break;
default:
break;
@@ -36,7 +36,7 @@
switch (color_fmt) {
case COLOR_FMT_NV12:
alignment = 128;
- stride = ALIGN(width, alignment);
+ stride = MSM_MEDIA_ALIGN(width, alignment);
break;
default:
break;
@@ -54,7 +54,7 @@
switch (color_fmt) {
case COLOR_FMT_NV12:
alignment = 32;
- sclines = ALIGN(height, alignment);
+ sclines = MSM_MEDIA_ALIGN(height, alignment);
break;
default:
break;
@@ -72,7 +72,7 @@
switch (color_fmt) {
case COLOR_FMT_NV12:
alignment = 16;
- sclines = ALIGN(((height + 1) >> 1), alignment);
+ sclines = MSM_MEDIA_ALIGN(((height + 1) >> 1), alignment);
break;
default:
break;
@@ -101,7 +101,7 @@
y_plane = y_stride * y_sclines;
uv_plane = uv_stride * uv_sclines + uv_alignment;
size = y_plane + uv_plane;
- size = ALIGN(size, 4096);
+ size = MSM_MEDIA_ALIGN(size, 4096);
break;
default:
break;
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 01276bd..4e92f70 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -8,7 +8,8 @@
#define ISP_VERSION_40 40
#define ISP_VERSION_32 32
-
+#define ISP_NATIVE_BUF_BIT 0x10000
+#define ISP_STATS_STREAM_BIT 0x80000000
enum ISP_START_PIXEL_PATTERN {
ISP_BAYER_RGRGRG,
@@ -160,6 +161,8 @@
uint32_t session_id;
uint32_t stream_id;
enum msm_isp_stats_type stats_type;
+ uint8_t comp_flag;
+ uint32_t framedrop_pattern;
uint32_t stream_handle;
};
struct msm_vfe_stats_stream_release_cmd {
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 2787e8d..b2a8d10 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -1,16 +1,3 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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 VCAP_FMT_H
#define VCAP_FMT_H
#include <linux/videodev2.h>
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 3571fad..4555b08 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6499,5 +6499,53 @@
struct afe_digital_clk_cfg clk_cfg;
} __packed;
+/*
+ * Opcode for AFE to start DTMF.
+ */
+#define AFE_PORTS_CMD_DTMF_CTL 0x00010102
+
+/** DTMF payload.*/
+struct afe_dtmf_generation_command {
+ struct apr_hdr hdr;
+
+ /*
+ * Duration of the DTMF tone in ms.
+ * -1 -> continuous,
+ * 0 -> disable
+ */
+ int64_t duration_in_ms;
+
+ /*
+ * The DTMF high tone frequency.
+ */
+ uint16_t high_freq;
+
+ /*
+ * The DTMF low tone frequency.
+ */
+ uint16_t low_freq;
+
+ /*
+ * The DTMF volume setting
+ */
+ uint16_t gain;
+
+ /*
+ * The number of ports to enable/disable on.
+ */
+ uint16_t num_ports;
+
+ /*
+ * The Destination ports - array .
+ * For DTMF on multiple ports, portIds needs to
+ * be populated numPorts times.
+ */
+ uint16_t port_ids;
+
+ /*
+ * variable for 32 bit alignment of APR packet.
+ */
+ uint16_t reserved;
+} __packed;
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index c12cbbe..5afbfad 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -1453,23 +1453,6 @@
u32 read_format;
} __attribute__((packed));
-#define ASM_STREAM_CMD_OPEN_LOOPBACK 0x00010D6E
-struct asm_stream_cmd_open_loopback {
- struct apr_hdr hdr;
- u32 mode_flags;
-/* Mode flags.
- * Bit 0-31: reserved; client should set these bits to 0
- */
- u16 src_endpointype;
- /* Endpoint type. 0 = Tx Matrix */
- u16 sink_endpointype;
- /* Endpoint type. 0 = Rx Matrix */
- u32 postprocopo_id;
-/* Postprocessor topology ID. Specifies the topology of
- * postprocessing algorithms.
- */
-} __packed;
-
#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
@@ -1915,4 +1898,5 @@
int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
/* SRS Studio Sound 3D end */
+
#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index c04cbfc..c34a397 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -40,7 +40,7 @@
};
struct msm_dai_auxpcm_pdata {
- const char *clk;
+ void *clk_cfg;
struct msm_dai_auxpcm_config mode_8k;
struct msm_dai_auxpcm_config mode_16k;
};
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index fdc3cb9..6e5e649 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -49,4 +49,8 @@
int adm_get_copp_id(int port_id);
+void adm_set_multi_ch_map(char *channel_map);
+
+void adm_get_multi_ch_map(char *channel_map);
+
#endif /* __Q6_ADM_V2_H__ */
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index e39d45c..552ed6a 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -126,7 +126,10 @@
int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz);
int afe_cmd_memory_unmap(u32 dma_addr_p);
int afe_cmd_memory_unmap_nowait(u32 dma_addr_p);
-
+void afe_set_dtmf_gen_rx_portid(u16 rx_port_id, int set);
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+ uint16_t high_freq,
+ uint16_t low_freq, uint16_t gain);
int afe_register_get_events(u16 port_id,
void (*cb) (uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv),
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index a436a6e..876d815 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -262,7 +262,8 @@
uint32_t rate, uint32_t channels);
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels);
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map);
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 275cdbe..ab75bff 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -155,6 +155,7 @@
struct mutex cmd_lock;
atomic_t cmd_state;
+ atomic_t cmd_close_state;
atomic_t time_flag;
atomic_t nowait_cmd_cnt;
wait_queue_head_t cmd_wait;
@@ -206,8 +207,6 @@
uint32_t rd_format,
uint32_t wr_format);
-int q6asm_open_loopack(struct audio_client *ac);
-
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d7521f8..2650b83 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -339,7 +339,7 @@
struct wcd9xxx_pdata *pdata;
u32 anc_slot;
-
+ bool anc_func;
bool no_mic_headset_override;
/* Delayed work to report long button press */
struct delayed_work mbhc_btn_dwork;
@@ -539,6 +539,48 @@
return 0;
}
+static int tabla_get_anc_func(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ ucontrol->value.integer.value[0] = (tabla->anc_func == true ? 1 : 0);
+ return 0;
+}
+
+static int tabla_put_anc_func(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ mutex_lock(&dapm->codec->mutex);
+
+ tabla->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+
+ dev_dbg(codec->dev, "%s: anc_func %x", __func__, tabla->anc_func);
+
+ if (tabla->anc_func == true) {
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_disable_pin(dapm, "HPHR");
+ snd_soc_dapm_disable_pin(dapm, "HPHL");
+ snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_enable_pin(dapm, "HPHR");
+ snd_soc_dapm_enable_pin(dapm, "HPHL");
+ snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
+ }
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
+ return 0;
+}
+
static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -987,6 +1029,10 @@
return 0;
}
+static const char *const tabla_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tabla_anc_func_enum =
+ SOC_ENUM_SINGLE_EXT(2, tabla_anc_func_text);
+
static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
static const struct soc_enum tabla_ear_pa_gain_enum[] = {
SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -1130,6 +1176,8 @@
SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
tabla_put_anc_slot),
+ SOC_ENUM_EXT("ANC Function", tabla_anc_func_enum, tabla_get_anc_func,
+ tabla_put_anc_func),
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -1321,7 +1369,7 @@
"ZERO", "EAR_HPH_L", "EAR_LINE_1",
};
-static const char *iir1_inp1_text[] = {
+static const char *const iir_inp1_text[] = {
"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
};
@@ -1469,7 +1517,10 @@
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
static const struct soc_enum iir1_inp1_mux_enum =
- SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir_inp1_text);
+
+static const struct soc_enum iir2_inp1_mux_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ2_B1_CTL, 0, 18, iir_inp1_text);
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -1694,6 +1745,9 @@
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+static const struct snd_kcontrol_new iir2_inp1_mux =
+ SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
+
static const struct snd_kcontrol_new anc1_mux =
SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
@@ -2476,111 +2530,6 @@
return 0;
}
-static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
- const char *filename;
- const struct firmware *fw;
- int i;
- int ret;
- int num_anc_slots;
- struct anc_header *anc_head;
- struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- u32 anc_writes_size = 0;
- int anc_size_remaining;
- u32 *anc_ptr;
- u16 reg;
- u8 mask, val, old_val;
-
- pr_debug("%s %d\n", __func__, event);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
-
- filename = "wcd9310/wcd9310_anc.bin";
-
- ret = request_firmware(&fw, filename, codec->dev);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
- ret);
- return -ENODEV;
- }
-
- if (fw->size < sizeof(struct anc_header)) {
- dev_err(codec->dev, "Not enough data\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- /* First number is the number of register writes */
- anc_head = (struct anc_header *)(fw->data);
- anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
- anc_size_remaining = fw->size - sizeof(struct anc_header);
- num_anc_slots = anc_head->num_anc_slots;
-
- if (tabla->anc_slot >= num_anc_slots) {
- dev_err(codec->dev, "Invalid ANC slot selected\n");
- release_firmware(fw);
- return -EINVAL;
- }
-
- for (i = 0; i < num_anc_slots; i++) {
-
- if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
- dev_err(codec->dev, "Invalid register format\n");
- release_firmware(fw);
- return -EINVAL;
- }
- anc_writes_size = (u32)(*anc_ptr);
- anc_size_remaining -= sizeof(u32);
- anc_ptr += 1;
-
- if (anc_writes_size * TABLA_PACKED_REG_SIZE
- > anc_size_remaining) {
- dev_err(codec->dev, "Invalid register format\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- if (tabla->anc_slot == i)
- break;
-
- anc_size_remaining -= (anc_writes_size *
- TABLA_PACKED_REG_SIZE);
- anc_ptr += anc_writes_size;
- }
- if (i == num_anc_slots) {
- dev_err(codec->dev, "Selected ANC slot not present\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- for (i = 0; i < anc_writes_size; i++) {
- TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
- mask, val);
- old_val = snd_soc_read(codec, reg);
- snd_soc_write(codec, reg, (old_val & ~mask) |
- (val & mask));
- }
- release_firmware(fw);
-
- TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
- /* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
- if (tabla->mbhc_polling_active)
- snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
- 0x80);
- TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
- break;
- case SND_SOC_DAPM_POST_PMD:
- /* unset TX7_MBHC_EN bit 7 */
- snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
-
- snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
- snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
- break;
- }
- return 0;
-}
/* called under codec_resource_lock acquisition */
static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
@@ -3283,6 +3232,160 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
+static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ const char *filename;
+ const struct firmware *fw;
+ int i;
+ int ret;
+ int num_anc_slots;
+ struct anc_header *anc_head;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u32 anc_writes_size = 0;
+ int anc_size_remaining;
+ u32 *anc_ptr;
+ u16 reg;
+ u8 mask, val, old_val;
+ u8 mbhc_micb_ctl_val;
+
+ pr_debug("%s: DAPM Event %d ANC func is %d\n",
+ __func__, event, tabla->anc_func);
+
+ if (tabla->anc_func == 0)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mbhc_micb_ctl_val = snd_soc_read(codec,
+ tabla->mbhc_bias_regs.ctl_reg);
+
+ if (!(mbhc_micb_ctl_val & 0x80)) {
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla_codec_switch_micbias(codec, 1);
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ }
+
+ filename = "wcd9310/wcd9310_anc.bin";
+
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct anc_header)) {
+ dev_err(codec->dev, "Not enough data\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ /* First number is the number of register writes */
+ anc_head = (struct anc_header *)(fw->data);
+ anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+ anc_size_remaining = fw->size - sizeof(struct anc_header);
+ num_anc_slots = anc_head->num_anc_slots;
+
+ if (tabla->anc_slot >= num_anc_slots) {
+ dev_err(codec->dev, "Invalid ANC slot selected\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_anc_slots; i++) {
+
+ if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+ anc_writes_size = (u32)(*anc_ptr);
+ anc_size_remaining -= sizeof(u32);
+ anc_ptr += 1;
+
+ if (anc_writes_size * TABLA_PACKED_REG_SIZE
+ > anc_size_remaining) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ if (tabla->anc_slot == i)
+ break;
+
+ anc_size_remaining -= (anc_writes_size *
+ TABLA_PACKED_REG_SIZE);
+ anc_ptr += anc_writes_size;
+ }
+ if (i == num_anc_slots) {
+ dev_err(codec->dev, "Selected ANC slot not present\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < anc_writes_size; i++) {
+ TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+ mask, val);
+ old_val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, (old_val & ~mask) |
+ (val & mask));
+ }
+ usleep_range(10000, 10000);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x30);
+ msleep(30);
+ release_firmware(fw);
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ /* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
+ if (tabla->mbhc_polling_active)
+ snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
+ 0x80);
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* schedule work is required because at the time HPH PA DAPM
+ * event callback is called by DAPM framework, CODEC dapm mutex
+ * would have been locked while snd_soc_jack_report also
+ * attempts to acquire same lock.
+ */
+ if (w->shift == 5) {
+ clear_bit(TABLA_HPHL_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ if (tabla->hph_status & SND_JACK_OC_HPHL)
+ schedule_work(&tabla->hphlocp_work);
+ } else if (w->shift == 4) {
+ clear_bit(TABLA_HPHR_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ if (tabla->hph_status & SND_JACK_OC_HPHR)
+ schedule_work(&tabla->hphrocp_work);
+ }
+
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla_codec_switch_micbias(codec, 0);
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
+ msleep(40);
+ /* unset TX7_MBHC_EN bit 7 */
+ snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_CDC_ANC1_CTL, 0x01, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_CDC_ANC2_CTL, 0x01, 0x00);
+ msleep(20);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+ break;
+ }
+ return 0;
+}
+
static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -3592,7 +3695,6 @@
{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
- {"ANC", NULL, "ANC1 FB MUX"},
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
@@ -3607,19 +3709,26 @@
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
- {"ANC", NULL, "ANC1 MUX"},
- {"ANC", NULL, "ANC2 MUX"},
+ {"ANC HEADPHONE", NULL, "ANC HPHL"},
+ {"ANC HEADPHONE", NULL, "ANC HPHR"},
+
+ {"ANC HPHL", NULL, "HPHL_PA_MIXER"},
+ {"ANC HPHR", NULL, "HPHR_PA_MIXER"},
+
{"ANC1 MUX", "ADC1", "ADC1"},
{"ANC1 MUX", "ADC2", "ADC2"},
{"ANC1 MUX", "ADC3", "ADC3"},
{"ANC1 MUX", "ADC4", "ADC4"},
+ {"ANC1 MUX", "DMIC1", "DMIC1"},
+ {"ANC1 MUX", "DMIC2", "DMIC2"},
+ {"ANC1 MUX", "DMIC3", "DMIC3"},
+ {"ANC1 MUX", "DMIC4", "DMIC4"},
{"ANC2 MUX", "ADC1", "ADC1"},
{"ANC2 MUX", "ADC2", "ADC2"},
{"ANC2 MUX", "ADC3", "ADC3"},
{"ANC2 MUX", "ADC4", "ADC4"},
- {"ANC", NULL, "CDC_CONN"},
-
+ {"ANC HPHR", NULL, "CDC_CONN"},
{"DAC1", "Switch", "RX1 CHAIN"},
{"HPHL DAC", "Switch", "RX1 CHAIN"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -3646,8 +3755,8 @@
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
- {"RX1 CHAIN", NULL, "ANC"},
- {"RX2 CHAIN", NULL, "ANC"},
+ {"RX1 MIX2", NULL, "ANC1 MUX"},
+ {"RX2 MIX2", NULL, "ANC2 MUX"},
{"CP", NULL, "RX_BIAS"},
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
@@ -3729,6 +3838,7 @@
{"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP1", "IIR2", "IIR2"},
{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3737,6 +3847,7 @@
{"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP2", "IIR2", "IIR2"},
{"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
@@ -3752,6 +3863,7 @@
{"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX2 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP1", "IIR2", "IIR2"},
{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3760,6 +3872,7 @@
{"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX2 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP2", "IIR2", "IIR2"},
{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3768,6 +3881,7 @@
{"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX3 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP1", "IIR2", "IIR2"},
{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3776,6 +3890,7 @@
{"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX3 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP2", "IIR2", "IIR2"},
{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3784,6 +3899,7 @@
{"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX4 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX4 MIX1 INP1", "IIR2", "IIR2"},
{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3792,6 +3908,7 @@
{"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX4 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX4 MIX1 INP2", "IIR2", "IIR2"},
{"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3800,6 +3917,7 @@
{"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX5 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX5 MIX1 INP1", "IIR2", "IIR2"},
{"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3808,6 +3926,7 @@
{"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX5 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX5 MIX1 INP2", "IIR2", "IIR2"},
{"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3816,6 +3935,7 @@
{"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX6 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX6 MIX1 INP1", "IIR2", "IIR2"},
{"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3824,6 +3944,7 @@
{"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX6 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX6 MIX1 INP2", "IIR2", "IIR2"},
{"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3832,6 +3953,7 @@
{"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
{"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX7 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP1", "IIR2", "IIR2"},
{"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
@@ -3840,12 +3962,20 @@
{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX7 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP2", "IIR2", "IIR2"},
+
{"RX1 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX2 INP1", "IIR2", "IIR2"},
{"RX1 MIX2 INP2", "IIR1", "IIR1"},
+ {"RX1 MIX2 INP2", "IIR2", "IIR2"},
{"RX2 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX2 INP1", "IIR2", "IIR2"},
{"RX2 MIX2 INP2", "IIR1", "IIR1"},
+ {"RX2 MIX2 INP2", "IIR2", "IIR2"},
{"RX3 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX3 MIX2 INP1", "IIR2", "IIR2"},
{"RX3 MIX2 INP2", "IIR1", "IIR1"},
+ {"RX3 MIX2 INP2", "IIR2", "IIR2"},
/* Decimator Inputs */
{"DEC1 MUX", "DMIC1", "DMIC1"},
@@ -3943,6 +4073,18 @@
{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2", NULL, "IIR2 INP1 MUX"},
+ {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP1 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP1 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP1 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
+
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
{"MIC BIAS1 External", NULL, "LDO_H"},
@@ -4052,6 +4194,14 @@
(reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
return 1;
+ /* ANC filter registers are not cacheable */
+ if ((reg >= TABLA_A_CDC_ANC1_FILT1_B1_CTL) &&
+ (reg <= TABLA_A_CDC_ANC1_FILT2_B3_CTL))
+ return 1;
+ if ((reg >= TABLA_A_CDC_ANC2_FILT1_B1_CTL) &&
+ (reg <= TABLA_A_CDC_ANC2_FILT2_B3_CTL))
+ return 1;
+
/* Digital gain register is not cacheable so we have to write
* the setting even it is the same
*/
@@ -5284,9 +5434,13 @@
SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
- SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
- tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+ SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tabla_codec_enable_anc,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU),
+
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
@@ -5386,6 +5540,9 @@
SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
SND_SOC_DAPM_PGA("IIR1", TABLA_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", TABLA_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
+
/* AUX PGA */
SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
@@ -6779,6 +6936,13 @@
* only report the mic line
*/
tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+ if (!tabla->mbhc_micbias_switched &&
+ tabla_is_hph_pa_on(codec)) {
+ /*If the headphone path is on, switch the micbias
+ to VDDIO to avoid noise due to button polling */
+ tabla_codec_switch_micbias(codec, 1);
+ pr_debug("%s: HPH path is still up\n", __func__);
+ }
msleep(100);
tabla_codec_start_hs_polling(codec);
} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
@@ -7201,7 +7365,6 @@
} else if (plug_type == PLUG_TYPE_HEADSET) {
pr_debug("%s: Headset detected\n", __func__);
tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
-
/* avoid false button press detect */
msleep(50);
tabla_codec_start_hs_polling(codec);
@@ -7685,6 +7848,7 @@
0x08, 0x00);
/* Turn off override */
tabla_turn_onoff_override(codec, false);
+ tabla_codec_switch_micbias(codec, 0);
}
}
@@ -8650,6 +8814,12 @@
"tabla_gpio_irq_resend");
tabla->gpio_irq_resend = false;
+ mutex_lock(&dapm->codec->mutex);
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+ snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
#ifdef CONFIG_DEBUG_FS
if (ret == 0) {
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index ad1546d..41a9cc5 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4902,11 +4902,6 @@
taiko = snd_soc_codec_get_drvdata(codec);
mutex_lock(&codec->mutex);
WCD9XXX_BCL_LOCK(&taiko->resmgr);
- if (spkr_drv_wrnd == 1) {
- wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
- }
- WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
if (codec->reg_def_copy) {
pr_debug("%s: Update ASOC cache", __func__);
@@ -4915,11 +4910,23 @@
codec->reg_size, GFP_KERNEL);
}
+ wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
+ if (spkr_drv_wrnd == 1)
+ snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
+ WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+
taiko_update_reg_defaults(codec);
taiko_codec_init_reg(codec);
ret = taiko_handle_pdata(taiko);
if (IS_ERR_VALUE(ret))
pr_err("%s: bad pdata\n", __func__);
+
+ wcd9xxx_mbhc_deinit(&taiko->mbhc);
+ ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
+ if (ret)
+ pr_err("%s: mbhc init failed %d\n", __func__, ret);
+ else
+ wcd9xxx_mbhc_start(&taiko->mbhc, taiko->mbhc.mbhc_cfg);
mutex_unlock(&codec->mutex);
return ret;
}
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 0f2a19c..8acc334 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.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
@@ -3177,23 +3177,28 @@
mbhc->resmgr = resmgr;
mbhc->resmgr->mbhc = mbhc;
- ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
- &mbhc->headset_jack);
- if (ret) {
- pr_err("%s: Failed to create new jack\n", __func__);
- return ret;
- }
+ if (mbhc->headset_jack.jack == NULL) {
+ ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
+ &mbhc->headset_jack);
+ if (ret) {
+ pr_err("%s: Failed to create new jack\n", __func__);
+ return ret;
+ }
- ret = snd_soc_jack_new(codec, "Button Jack", WCD9XXX_JACK_BUTTON_MASK,
- &mbhc->button_jack);
- if (ret) {
- pr_err("Failed to create new jack\n");
- return ret;
- }
+ ret = snd_soc_jack_new(codec, "Button Jack",
+ WCD9XXX_JACK_BUTTON_MASK,
+ &mbhc->button_jack);
+ if (ret) {
+ pr_err("Failed to create new jack\n");
+ return ret;
+ }
- INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork, wcd9xxx_mbhc_fw_read);
- INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
- INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork, wcd9xxx_mbhc_insert_work);
+ INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
+ wcd9xxx_mbhc_fw_read);
+ INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
+ INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork,
+ wcd9xxx_mbhc_insert_work);
+ }
/* Register event notifier */
mbhc->nblock.notifier_call = wcd9xxx_event_notify;
@@ -3294,6 +3299,11 @@
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);
+ wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+ wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
+ wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+
if (mbhc->mbhc_fw)
release_firmware(mbhc->mbhc_fw);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 0ab650e..17edd4a 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -198,19 +198,44 @@
void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
{
int old_bg_audio_users, old_bg_mbhc_users;
+ int old_clk_rco_users, old_clk_mclk_users;
+ pr_debug("%s: enter\n", __func__);
WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
old_bg_audio_users = resmgr->bg_audio_users;
- resmgr->bg_audio_users = 0;
old_bg_mbhc_users = resmgr->bg_mbhc_users;
+ old_clk_rco_users = resmgr->clk_rco_users;
+ old_clk_mclk_users = resmgr->clk_mclk_users;
+ resmgr->bg_audio_users = 0;
resmgr->bg_mbhc_users = 0;
+ resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
+ resmgr->clk_rco_users = 0;
+ resmgr->clk_mclk_users = 0;
+ resmgr->clk_type = WCD9XXX_CLK_OFF;
- while (old_bg_audio_users && --old_bg_audio_users)
- wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
+ if (old_bg_audio_users) {
+ while (old_bg_audio_users--)
+ wcd9xxx_resmgr_get_bandgap(resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ }
- while (old_bg_mbhc_users && --old_bg_mbhc_users)
- wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+ if (old_bg_mbhc_users) {
+ while (old_bg_mbhc_users--)
+ wcd9xxx_resmgr_get_bandgap(resmgr,
+ WCD9XXX_BANDGAP_MBHC_MODE);
+ }
+
+ if (old_clk_mclk_users) {
+ while (old_clk_mclk_users--)
+ wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_MCLK);
+ }
+
+ if (old_clk_rco_users) {
+ while (old_clk_rco_users--)
+ wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_RCO);
+ }
+ pr_debug("%s: leave\n", __func__);
}
/*
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index e5f0208..4c8d2e3 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,7 +55,8 @@
# for MSM 8960 sound card driver
obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index eadb365..8eac69e 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -22,12 +22,12 @@
#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 <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9320.h"
-
/* Spk control */
#define MDM9625_SPK_ON 1
@@ -56,21 +56,24 @@
struct clk *cdc_bit_clk;
u32 cnt;
};
-
-/* MI2S clock */
-struct mdm_mi2s_clk {
- struct clk *cdc_cr_clk;
- struct clk *cdc_osr_clk;
- u32 clk_usrs;
-};
-
struct mdm9625_machine_data {
u32 mclk_freq;
struct msm_i2s_gpio *mclk_pin;
struct msm_i2s_ctrl *pri_ctrl;
-
+ u32 prim_clk_usrs;
};
+static const struct afe_clk_cfg lpass_default = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+
#define GPIO_NAME_INDEX 0
#define DT_PARSE_INDEX 1
@@ -86,7 +89,6 @@
{"MI2S_MCLK", "prim-i2s-gpio-mclk"},
};
-static struct mdm_mi2s_clk clk_ctl;
static struct mutex cdc_mclk_mutex;
static int mdm9625_mi2s_rx_ch = 1;
static int mdm9625_mi2s_tx_ch = 1;
@@ -209,63 +211,51 @@
}
static int mdm9625_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd, bool enable)
{
- struct mdm_mi2s_clk *clk = &clk_ctl;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_card *card = rtd->card;
- struct clk *bclk = NULL;
struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
+ struct afe_clk_cfg *lpass_clk = NULL;
int ret = 0;
if (pdata == NULL) {
pr_err("%s:platform data is null\n", __func__);
- return -ENODEV;
+ return -ENOMEM;
}
- bclk = pdata->pri_ctrl->cdc_bit_clk;
-
+ lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
+ if (lpass_clk == NULL) {
+ pr_err("%s:Failed to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+ memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
+ pr_debug("%s:enable = %x\n", __func__, enable);
if (enable) {
- if (clk->clk_usrs == 0) {
- /* Set rate core and ibit clock */
- clk_set_rate(clk->cdc_cr_clk, pdata->mclk_freq);
- /* Enable clocks. core clock need not be enabled.
- * Enabling branch clocks indirectly enables
- * core clock.
- */
- ret = clk_prepare_enable(clk->cdc_osr_clk);
- if (ret != 0) {
- pr_err("Fail to enable cdc_osr_clk\n");
- goto exit_osrclk_err;
- }
- }
- clk->clk_usrs++;
- /* ibit clock */
- bclk = clk_get(cpu_dai->dev, "ibit_clk");
- if (IS_ERR(bclk)) {
- pr_err("%s: Failed to request Bit %ld\n"
- "CPU dai name %s\n", __func__,
- PTR_ERR(bclk),
- cpu_dai->dev->driver->name);
- return -ENODEV ;
- }
- clk_set_rate(bclk, MDM_IBIT_CLK_DIV_1P56MHZ);
- ret = clk_prepare_enable(bclk);
- if (ret != 0) {
- pr_err("Fail to enable cdc_bit_clk\n");
- goto exit_bclk_err;
- }
- return ret;
+ if (pdata->prim_clk_usrs == 0) {
+ lpass_clk->clk_val2 = pdata->mclk_freq;
+ lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_BOTH_VALID;
+ } else
+ lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
+ ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+ else
+ pdata->prim_clk_usrs++;
} else {
- if (clk->clk_usrs > 0)
- clk->clk_usrs--;
- ret = 0;
- goto exit_bclk_err;
+ if (pdata->prim_clk_usrs > 0)
+ pdata->prim_clk_usrs--;
+ if (pdata->prim_clk_usrs == 0) {
+ lpass_clk->clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_BOTH_VALID;
+ } else
+ lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
+ lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
}
-exit_bclk_err:
- clk_disable_unprepare(bclk);
- clk_put(bclk);
-exit_osrclk_err:
- if (clk->clk_usrs == 0)
- clk_disable_unprepare(clk->cdc_osr_clk);
- bclk = NULL;
+ pr_debug("%s: clk 1 = %x clk2 = %x mode = %x\n",
+ __func__, lpass_clk->clk_val1,
+ lpass_clk->clk_val2,
+ lpass_clk->clk_set_mode);
+ kfree(lpass_clk);
return ret;
}
@@ -419,35 +409,51 @@
int ret = 0;
struct mdm9625_machine_data *pdata =
snd_soc_card_get_drvdata(codec->card);
- struct mdm_mi2s_clk *clk = &clk_ctl;
+ struct afe_clk_cfg *lpass_clk = NULL;
- pr_debug("%s: enable = %d codec name %s\n", __func__,
- enable, codec->name);
+ pr_debug("%s: enable = %d codec name %s enable %x\n",
+ __func__, enable, codec->name, enable);
+ lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
+ if (lpass_clk == NULL) {
+ pr_err("%s:Failed to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
mutex_lock(&cdc_mclk_mutex);
-
+ memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
if (enable) {
- if (clk->clk_usrs == 0) {
- /* Set rate core and ibit clock */
- clk_set_rate(clk->cdc_cr_clk, pdata->mclk_freq);
- /* Enable clocks. core clock need not be enabled.
- * Enabling branch clocks indirectly enables
- * core clock.
- */
- ret = clk_prepare_enable(clk->cdc_osr_clk);
- if (ret != 0)
- pr_err("Fail to enable cdc_osr_clk\n");
+ if (pdata->prim_clk_usrs == 0) {
+ lpass_clk->clk_val2 = pdata->mclk_freq;
+ lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
+ ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
+ if (ret < 0) {
+ pr_err("%s:afe_set_lpass_clock failed\n",
+ __func__);
+ goto err;
+ }
}
- clk->clk_usrs++;
+ pdata->prim_clk_usrs++;
taiko_mclk_enable(codec, 1, dapm);
-
} else {
- if (clk->clk_usrs > 0)
- clk->clk_usrs--;
- if (clk->clk_usrs == 0)
- clk_disable_unprepare(clk->cdc_osr_clk);
+ if (pdata->prim_clk_usrs > 0)
+ pdata->prim_clk_usrs--;
+ if (pdata->prim_clk_usrs == 0) {
+ lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
+ lpass_clk->clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
+ if (ret < 0) {
+ pr_err("%s:afe_set_lpass_clock failed\n",
+ __func__);
+ goto err;
+ }
+ }
taiko_mclk_enable(codec, 0, dapm);
}
+ pr_debug("%s: clk2 = %x mode = %x\n",
+ __func__, lpass_clk->clk_val2,
+ lpass_clk->clk_set_mode);
+err:
mutex_unlock(&cdc_mclk_mutex);
+ kfree(lpass_clk);
return ret;
}
@@ -507,38 +513,6 @@
mdm9625_mi2s_tx_ch_put),
};
-static int msm9625_set_codec_mclk(struct snd_soc_pcm_runtime *rtd, bool enable)
-{
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct mdm_mi2s_clk *clk = &clk_ctl;
- int ret = 0;
-
- if (clk->clk_usrs == 0) {
- clk->cdc_cr_clk = clk_get(cpu_dai->dev, "core_clk");
- if (IS_ERR(clk->cdc_cr_clk)) {
- pr_err("%s: Failed to Core clk %ld\n"
- "CPU dai name %s\n", __func__,
- PTR_ERR(clk->cdc_cr_clk),
- cpu_dai->dev->driver->name);
- return -ENODEV ;
- }
- /* osr clock */
- clk->cdc_osr_clk = clk_get(cpu_dai->dev, "osr_clk");
- if (IS_ERR(clk->cdc_osr_clk)) {
- pr_err("%s: Failed to request OSR %ld\n"
- "CPU dai name %s\n", __func__,
- PTR_ERR(clk->cdc_osr_clk),
- cpu_dai->dev->driver->name);
- clk_put(clk->cdc_cr_clk);
- return -ENODEV ;
- }
- } else {
- pr_err("%s: Failed to get MCLK\n", __func__);
- ret = -ENODEV ;
- }
- return ret;
-}
-
static int mdm9625_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -565,10 +539,6 @@
snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
snd_soc_dapm_sync(dapm);
- /* start mbhc */
- err = msm9625_set_codec_mclk(rtd, true);
- if (err < 0)
- return err;
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration)
err = taiko_hs_detect(codec, &mbhc_cfg);
@@ -725,6 +695,64 @@
.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 = "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 = "DTMF RX Hostless",
+ .stream_name = "DTMF RX Hostless",
+ .cpu_dai_name = "DTMF_RX_HOSTLESS",
+ .platform_name = "msm-pcm-dtmf",
+ .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,
+ .be_id = MSM_FRONTEND_DAI_DTMF_RX,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ },
+ {
+ .name = "DTMF TX",
+ .stream_name = "DTMF TX",
+ .cpu_dai_name = "msm-dai-stub",
+ .platform_name = "msm-pcm-dtmf",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .ignore_suspend = 1,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_MI2S_RX,
@@ -751,6 +779,26 @@
.be_hw_params_fixup = &mdm9625_mi2s_tx_be_hw_params_fixup,
.ops = &mdm9625_mi2s_be_ops,
},
+ {
+ .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,
+ },
+ {
+ .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,
+ },
};
static struct snd_soc_card snd_soc_card_mdm9625 = {
@@ -851,11 +899,16 @@
{
int ret;
struct snd_soc_card *card = &snd_soc_card_mdm9625;
- struct mdm_mi2s_clk *clk = &clk_ctl;
struct mdm9625_machine_data *pdata;
+ enum apr_subsys_state q6_state;
+ q6_state = apr_get_q6_state();
+ if (q6_state != APR_SUBSYS_LOADED) {
+ dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n",
+ __func__, q6_state);
+ return -EPROBE_DEFER;
+ }
mutex_init(&cdc_mclk_mutex);
- clk->clk_usrs = 0;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
return -EINVAL;
@@ -885,12 +938,13 @@
goto err;
}
/* At present only 12.288MHz is supported on MDM. */
- if (pdata->mclk_freq != MDM_MCLK_CLK_12P288MHZ) {
+ if (q6afe_check_osr_clk_freq(pdata->mclk_freq)) {
dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
pdata->mclk_freq);
ret = -EINVAL;
goto err;
}
+ pdata->prim_clk_usrs = 0;
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, pdata);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 784b650..cf0d4cd 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -229,17 +229,6 @@
.rate_min = 8000,
.rate_max = 48000,
},
- .capture = {
- .stream_name = "MultiMedia6 Capture",
- .aif_name = "MM_UL6",
- .rates = (SNDRV_PCM_RATE_8000_48000|
- SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 1,
- .channels_max = 8,
- .rate_min = 8000,
- .rate_max = 48000,
- },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia6",
},
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
deleted file mode 100644
index 55f29a5..0000000
--- a/sound/soc/msm/msm-pcm-loopback.c
+++ /dev/null
@@ -1,327 +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/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/apr_audio.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/q6asm.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <asm/dma.h>
-#include <linux/dma-mapping.h>
-
-#include "msm-pcm-routing.h"
-
-struct msm_pcm {
- struct snd_pcm_substream *playback_substream;
- struct snd_pcm_substream *capture_substream;
-
- int instance;
-
- struct mutex lock;
-
- uint32_t samp_rate;
- uint32_t channel_mode;
-
- int playback_start;
- int capture_start;
- int session_id;
- struct audio_client *audio_client;
-};
-
-static void stop_pcm(struct msm_pcm *pcm);
-
-static struct msm_pcm pcm_info;
-
-static const struct snd_pcm_hardware dummy_pcm_hardware = {
- .formats = 0xffffffff,
- .channels_min = 1,
- .channels_max = UINT_MAX,
-
- /* Random values to keep userspace happy when checking constraints */
- .info = SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .buffer_bytes_max = 128*1024,
- .period_bytes_min = PAGE_SIZE,
- .period_bytes_max = PAGE_SIZE*2,
- .periods_min = 2,
- .periods_max = 128,
-};
-
-static void event_handler(uint32_t opcode,
- uint32_t token, uint32_t *payload, void *priv)
-{
- pr_debug("%s\n", __func__);
- switch (opcode) {
- case APR_BASIC_RSP_RESULT:
- pr_debug("%s: opcode[0x%x]\n", __func__, opcode);
- break;
- default:
- pr_err("Not Supported Event opcode[0x%x]\n", opcode);
- break;
- }
-}
-
-static int msm_pcm_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct msm_pcm *pcm = &pcm_info;
- int ret = 0;
-
- mutex_lock(&pcm->lock);
-
- snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- pcm->playback_substream = substream;
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- pcm->capture_substream = substream;
-
- pcm->instance++;
- pr_debug("%s: pcm out open: %d,%d\n", __func__,
- pcm->instance, substream->stream);
- if (pcm->instance == 2) {
- struct snd_soc_pcm_runtime *soc_pcm_rx =
- pcm->playback_substream->private_data;
- struct snd_soc_pcm_runtime *soc_pcm_tx =
- pcm->capture_substream->private_data;
- if (pcm->audio_client != NULL)
- stop_pcm(pcm);
-
- pcm->audio_client = q6asm_audio_client_alloc(
- (app_cb)event_handler, pcm);
- if (!pcm->audio_client) {
- pr_err("%s: Could not allocate memory\n", __func__);
- mutex_unlock(&pcm->lock);
- return -ENOMEM;
- }
- pcm->session_id = pcm->audio_client->session;
- pcm->audio_client->perf_mode = false;
- ret = q6asm_open_loopack(pcm->audio_client);
- if (ret < 0) {
- pr_err("%s: pcm out open failed\n", __func__);
- q6asm_audio_client_free(pcm->audio_client);
- mutex_unlock(&pcm->lock);
- return -ENOMEM;
- }
- msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
- pcm->audio_client->perf_mode,
- pcm->session_id, pcm->capture_substream->stream);
- msm_pcm_routing_reg_phy_stream(soc_pcm_rx->dai_link->be_id,
- pcm->audio_client->perf_mode,
- pcm->session_id, pcm->playback_substream->stream);
- }
- pr_debug("%s: Instance = %d, Stream ID = %s\n",
- __func__ , pcm->instance, substream->pcm->id);
- runtime->private_data = pcm;
-
- mutex_unlock(&pcm->lock);
-
- return 0;
-}
-
-int msm_set_lb_volume(unsigned volume)
-{
- int rc = 0;
- if (pcm_info.audio_client != NULL) {
- pr_debug("%s: apply loopback vol:%d\n", __func__, volume);
- rc = q6asm_set_volume(pcm_info.audio_client, volume);
- if (rc < 0) {
- pr_err("%s: Send Volume command failed" \
- " rc=%d\n", __func__, rc);
- }
- }
- return rc;
-}
-
-static void stop_pcm(struct msm_pcm *pcm)
-{
- struct snd_soc_pcm_runtime *soc_pcm_rx =
- pcm->playback_substream->private_data;
- struct snd_soc_pcm_runtime *soc_pcm_tx =
- pcm->capture_substream->private_data;
-
- if (pcm->audio_client == NULL)
- return;
- q6asm_cmd(pcm->audio_client, CMD_CLOSE);
-
- msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
- SNDRV_PCM_STREAM_PLAYBACK);
- msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
- SNDRV_PCM_STREAM_CAPTURE);
- q6asm_audio_client_free(pcm->audio_client);
- pcm->audio_client = NULL;
-}
-
-static int msm_pcm_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct msm_pcm *pcm = runtime->private_data;
- int ret = 0;
-
- mutex_lock(&pcm->lock);
-
- pr_debug("%s: end pcm call:%d\n", __func__, substream->stream);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- pcm->playback_start = 0;
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- pcm->capture_start = 0;
-
- pcm->instance--;
- if (!pcm->playback_start || !pcm->capture_start) {
- pr_debug("%s: end pcm call\n", __func__);
- stop_pcm(pcm);
- }
-
- mutex_unlock(&pcm->lock);
- return ret;
-}
-
-static int msm_pcm_prepare(struct snd_pcm_substream *substream)
-{
- int ret = 0;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct msm_pcm *pcm = runtime->private_data;
-
- mutex_lock(&pcm->lock);
-
- pr_debug("%s: ASM loopback stream:%d\n", __func__, substream->stream);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (!pcm->playback_start)
- pcm->playback_start = 1;
- } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (!pcm->capture_start)
- pcm->capture_start = 1;
- }
- mutex_unlock(&pcm->lock);
-
- return ret;
-}
-
-static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct msm_pcm *pcm = runtime->private_data;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- pr_debug("%s: playback_start:%d,capture_start:%d\n", __func__,
- pcm->playback_start, pcm->capture_start);
- if (pcm->playback_start && pcm->capture_start)
- q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
- break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
- __func__, pcm->playback_start, pcm->capture_start);
- if (pcm->playback_start && pcm->capture_start)
- q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
-
- pr_debug("%s: ASM loopback\n", __func__);
-
- return snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(params));
-}
-
-static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static struct snd_pcm_ops msm_pcm_ops = {
- .open = msm_pcm_open,
- .hw_params = msm_pcm_hw_params,
- .hw_free = msm_pcm_hw_free,
- .close = msm_pcm_close,
- .prepare = msm_pcm_prepare,
- .trigger = msm_pcm_trigger,
-};
-
-
-static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_card *card = rtd->card->snd_card;
- int ret = 0;
-
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- return ret;
-}
-
-static struct snd_soc_platform_driver msm_soc_platform = {
- .ops = &msm_pcm_ops,
- .pcm_new = msm_asoc_pcm_new,
-};
-
-static __devinit int msm_pcm_probe(struct platform_device *pdev)
-{
- pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
- return snd_soc_register_platform(&pdev->dev,
- &msm_soc_platform);
-}
-
-static int msm_pcm_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver msm_pcm_driver = {
- .driver = {
- .name = "msm-pcm-loopback",
- .owner = THIS_MODULE,
- },
- .probe = msm_pcm_probe,
- .remove = __devexit_p(msm_pcm_remove),
-};
-
-static int __init msm_soc_platform_init(void)
-{
- memset(&pcm_info, 0, sizeof(struct msm_pcm));
- mutex_init(&pcm_info.lock);
-
- return platform_driver_register(&msm_pcm_driver);
-}
-module_init(msm_soc_platform_init);
-
-static void __exit msm_soc_platform_exit(void)
-{
- mutex_destroy(&pcm_info.lock);
- platform_driver_unregister(&msm_pcm_driver);
-}
-module_exit(msm_soc_platform_exit);
-
-MODULE_DESCRIPTION("ASM loopback module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index aaae373..6cf74d5 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1608,9 +1608,6 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1647,9 +1644,6 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1668,9 +1662,6 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1767,12 +1758,6 @@
msm_routing_put_audio_mixer),
};
-static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
- SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
-
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2564,7 +2549,6 @@
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
- SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2672,8 +2656,6 @@
mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
- SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
- mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2848,7 +2830,6 @@
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -2867,7 +2848,6 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2882,14 +2862,12 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
- {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -2898,14 +2876,12 @@
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
- {"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 202e7ea..b571483 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 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
@@ -145,8 +145,6 @@
int lpa_set_volume(unsigned volume);
-int msm_set_lb_volume(unsigned volume);
-
int msm_routing_check_backend_enabled(int fedai_id);
int multi_ch_pcm_set_volume(unsigned volume);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 196cb44..d674b8b 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -1135,22 +1135,6 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
- {
- .name = "MSM8960 FM",
- .stream_name = "MultiMedia6",
- .cpu_dai_name = "MultiMedia6",
- .platform_name = "msm-pcm-loopback",
- .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,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- /* this dainlink has playback support */
- .ignore_pmdown_time = 1,
- .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
- },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 6712941..1c47e6e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -137,6 +137,7 @@
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
+static int msm_hdmi_rx_ch = 2;
static struct mutex cdc_mclk_mutex;
static struct q_clkdiv *codec_clk;
@@ -401,6 +402,9 @@
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),
@@ -413,6 +417,8 @@
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"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
@@ -488,6 +494,30 @@
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),
@@ -571,7 +601,10 @@
pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
channels->min, channels->max);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_hdmi_rx_ch;
return 0;
}
@@ -742,6 +775,7 @@
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -753,6 +787,8 @@
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
SOC_ENUM_EXT("AUX PCM SampleRate", msm8974_auxpcm_enum[0],
msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+ msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 58a07d6..4c50b53 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -1267,6 +1267,8 @@
int ret = 0, i = 0;
/* Assumes port_ids have already been validated during adm_open */
int index = afe_get_port_index(copp_id);
+ int copp_cnt;
+
if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: invalid port idx %d token %d\n",
__func__, index, copp_id);
@@ -1289,9 +1291,19 @@
route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
route.num_sessions = 1;
route.session[0].id = session_id;
- route.session[0].num_copps = num_copps;
- for (i = 0; i < num_copps; i++) {
+ if (num_copps < ADM_MAX_COPPS) {
+ copp_cnt = num_copps;
+ } else {
+ copp_cnt = ADM_MAX_COPPS;
+ /* print out warning for now as playback/capture to/from
+ * COPPs more than maximum allowed is extremely unlikely
+ */
+ pr_warn("%s: max out routable COPPs\n", __func__);
+ }
+
+ route.session[0].num_copps = copp_cnt;
+ for (i = 0; i < copp_cnt; i++) {
int tmp;
port_id[i] = afe_convert_virtual_to_portid(port_id[i]);
@@ -1304,7 +1316,8 @@
route.session[0].copp_id[i] =
atomic_read(&this_adm.copp_id[tmp]);
}
- if (num_copps % 2)
+
+ if (copp_cnt % 2)
route.session[0].copp_id[i] = 0;
switch (path) {
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index f29f02e..9558fa4 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, .qualcomm.com. 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
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 8ec2e94..1d21461 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -912,13 +912,16 @@
case ASM_STREAM_CMD_OPEN_WRITE:
case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
case ASM_STREAM_CMD_OPEN_READWRITE:
- case ASM_STREAM_CMD_OPEN_LOOPBACK:
case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
- if (atomic_read(&ac->cmd_state) && wakeup_flag) {
+ if (payload[0] == ASM_STREAM_CMD_CLOSE) {
+ atomic_set(&ac->cmd_close_state, 0);
+ wake_up(&ac->cmd_wait);
+ } else if (atomic_read(&ac->cmd_state) &&
+ wakeup_flag) {
atomic_set(&ac->cmd_state, 0);
pr_debug("response payload[1]:%d",
payload[1]);
@@ -1849,45 +1852,6 @@
return -EINVAL;
}
-int q6asm_open_loopack(struct audio_client *ac)
-{
- int rc = 0x00;
- struct asm_stream_cmd_open_loopback open;
-
- if ((ac == NULL) || (ac->apr == NULL)) {
- pr_err("APR handle NULL\n");
- return -EINVAL;
- }
- pr_debug("%s: session[%d]", __func__, ac->session);
-
- q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
- open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
-
- open.mode_flags = 0;
- open.src_endpointype = 0;
- open.sink_endpointype = 0;
- /* source endpoint : matrix */
- open.postprocopo_id = get_asm_topology();
- if (open.postprocopo_id == 0)
- open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
-
- rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
- if (rc < 0) {
- pr_err("open failed op[0x%x]rc[%d]\n", \
- open.hdr.opcode, rc);
- goto fail_cmd;
- }
- rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) == 0), 5*HZ);
- if (!rc) {
- pr_err("timeout. waited for OPEN_LOOPBACK rc[%d]\n", rc);
- goto fail_cmd;
- }
- return 0;
-fail_cmd:
- return -EINVAL;
-}
-
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
@@ -3924,7 +3888,8 @@
case CMD_CLOSE:
pr_debug("%s:CMD_CLOSE\n", __func__);
hdr.opcode = ASM_STREAM_CMD_CLOSE;
- state = &ac->cmd_state;
+ atomic_set(&ac->cmd_close_state, 1);
+ state = &ac->cmd_close_state;
break;
default:
pr_err("Invalid format[%d]\n", cmd);
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 58eec3c..69c0976 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,6 +1,6 @@
snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o
snd-soc-qdsp6v2-objs += msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o
-obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o msm-dai-stub-v2.o
obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o rtac.o
ocmem-audio-objs += audio_ocmem.o
obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index f151e51..145f095 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -590,7 +590,7 @@
pr_debug("%s\n", __func__);
audio_ocmem_lcl.audio_ocmem_workqueue =
alloc_workqueue("ocmem_audio_client_driver_audio",
- WQ_NON_REENTRANT, 0);
+ WQ_NON_REENTRANT | WQ_UNBOUND, 0);
if (!audio_ocmem_lcl.audio_ocmem_workqueue) {
pr_err("%s: Failed to create ocmem audio work queue\n",
__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 48d9e1e..329d293 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.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,11 +24,20 @@
#include <sound/q6afe-v2.h>
#include <sound/msm-dai-q6-v2.h>
+#define HDMI_RX_CA_MAX 0x32
+
enum {
STATUS_PORT_STARTED, /* track if AFE port has started */
STATUS_MAX
};
+struct msm_hdmi_ca {
+ bool set_ca;
+ u32 ca;
+};
+
+static struct msm_hdmi_ca hdmi_ca = { false, 0x0 };
+
struct msm_dai_q6_hdmi_dai_data {
DECLARE_BITMAP(status_mask, STATUS_MAX);
u32 rate;
@@ -57,6 +66,20 @@
return 0;
}
+static int msm_dai_q6_hdmi_ca_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ hdmi_ca.ca = ucontrol->value.integer.value[0];
+ hdmi_ca.set_ca = true;
+ return 0;
+}
+
+static int msm_dai_q6_hdmi_ca_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hdmi_ca.ca;
+ return 0;
+}
/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
* 0: linear PCM
@@ -75,6 +98,10 @@
SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
msm_dai_q6_hdmi_format_get,
msm_dai_q6_hdmi_format_put),
+ SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0,
+ HDMI_RX_CA_MAX, 0, 1,
+ msm_dai_q6_hdmi_ca_get,
+ msm_dai_q6_hdmi_ca_put),
};
/* Current implementation assumes hw_param is called once
@@ -152,6 +179,10 @@
struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc = 0;
+ if (hdmi_ca.set_ca)
+ dai_data->port_config.hdmi_multi_ch.channel_allocation =
+ hdmi_ca.ca;
+
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
rc = afe_port_start(dai->id, &dai_data->port_config,
dai_data->rate);
@@ -186,6 +217,12 @@
rc = snd_ctl_add(dai->card->snd_card,
snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &hdmi_config_controls[1];
+
+ rc = snd_ctl_add(dai->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
+
return rc;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index ab92269..cf7f182 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -28,6 +28,15 @@
#include <sound/pcm_params.h>
#include <mach/clk.h>
+static const struct afe_clk_cfg lpass_clk_cfg_default = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_OSR_CLK_2_P048_MHZ,
+ 0,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_CLK1_VALID,
+ 0,
+};
enum {
STATUS_PORT_STARTED, /* track if AFE port has started */
STATUS_MAX
@@ -76,11 +85,6 @@
SOC_ENUM_SINGLE_EXT(4, mi2s_format),
};
-static struct clk *pcm_src_clk;
-static struct clk *pcm_branch_clk;
-static struct clk *pcm_oe_src_clk;
-static struct clk *pcm_oe_branch_clk;
-
static DEFINE_MUTEX(aux_pcm_mutex);
static int aux_pcm_count;
@@ -148,6 +152,9 @@
struct snd_soc_dai *dai)
{
int rc = 0;
+ struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
+ struct afe_clk_cfg lpass_pcm_oe_clk;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
mutex_lock(&aux_pcm_mutex);
@@ -176,6 +183,9 @@
pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
dai->id, aux_pcm_count);
+ auxpcm_pdata = (struct msm_dai_auxpcm_pdata *)dai->dev->platform_data;
+ lpass_pcm_src_clk = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
+
rc = afe_close(PCM_RX); /* can block */
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
@@ -184,8 +194,14 @@
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close AUX PCM TX port\n");
- clk_disable_unprepare(pcm_branch_clk);
- clk_disable_unprepare(pcm_oe_branch_clk);
+ lpass_pcm_src_clk->clk_val1 = 0;
+ afe_set_lpass_clock(PCM_TX, lpass_pcm_src_clk);
+ afe_set_lpass_clock(PCM_RX, lpass_pcm_src_clk);
+
+ memcpy(&lpass_pcm_oe_clk, &lpass_clk_cfg_default,
+ sizeof(struct afe_clk_cfg));
+ lpass_pcm_oe_clk.clk_val1 = 0;
+ afe_set_lpass_clock(PCM_RX, &lpass_pcm_oe_clk);
mutex_unlock(&aux_pcm_mutex);
}
@@ -197,8 +213,11 @@
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
int rc = 0;
unsigned long pcm_clk_rate;
+ struct afe_clk_cfg lpass_pcm_oe_clk;
+ struct afe_clk_cfg *lpass_pcm_src_clk = NULL;
auxpcm_pdata = dai->dev->platform_data;
+ lpass_pcm_src_clk = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
mutex_lock(&aux_pcm_mutex);
@@ -252,32 +271,32 @@
return -EINVAL;
}
- rc = clk_set_rate(pcm_src_clk, pcm_clk_rate);
+ memcpy(lpass_pcm_src_clk, &lpass_clk_cfg_default,
+ sizeof(struct afe_clk_cfg));
+ lpass_pcm_src_clk->clk_val1 = pcm_clk_rate;
+ memcpy(&lpass_pcm_oe_clk, &lpass_clk_cfg_default,
+ sizeof(struct afe_clk_cfg));
+ lpass_pcm_oe_clk.clk_val1 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+
+ rc = afe_set_lpass_clock(PCM_RX, lpass_pcm_src_clk);
if (rc < 0) {
- pr_err("%s: clk_set_rate failed\n", __func__);
- mutex_unlock(&aux_pcm_mutex);
+ pr_err("%s:afe_set_lpass_clock on RX pcm_src_clk failed\n",
+ __func__);
goto fail;
}
- rc = clk_prepare_enable(pcm_branch_clk);
- if (rc) {
- pr_err("%s: clk enable failed\n", __func__);
- mutex_unlock(&aux_pcm_mutex);
- goto fail;
- }
-
- rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
+ rc = afe_set_lpass_clock(PCM_TX, lpass_pcm_src_clk);
if (rc < 0) {
- pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
- mutex_unlock(&aux_pcm_mutex);
+ pr_err("%s:afe_set_lpass_clock on TX pcm_src_clk failed\n",
+ __func__);
goto fail;
}
- rc = clk_prepare_enable(pcm_oe_branch_clk);
- if (rc) {
- pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
- mutex_unlock(&aux_pcm_mutex);
+ rc = afe_set_lpass_clock(PCM_RX, &lpass_pcm_oe_clk);
+ if (rc < 0) {
+ pr_err("%s:afe_set_lpass_clock on pcm_oe_clk failed\n",
+ __func__);
goto fail;
}
@@ -285,9 +304,8 @@
afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
- mutex_unlock(&aux_pcm_mutex);
-
fail:
+ mutex_unlock(&aux_pcm_mutex);
return rc;
}
@@ -331,49 +349,6 @@
dai->dev->platform_data = auxpcm_pdata;
dai->id = dai->dev->id;
- mutex_lock(&aux_pcm_mutex);
-
- /*
- * The clk name for AUX PCM operation is passed as platform
- * data to the cpu driver, since cpu drive is unaware of any
- * boarc specific configuration.
- */
- if ((!pcm_src_clk) || (!pcm_branch_clk)) {
- pcm_src_clk = clk_get(dai->dev, auxpcm_pdata->clk);
-
- if (IS_ERR(pcm_src_clk)) {
- pr_err("%s: could not get pcm_src_clk\n", __func__);
- pcm_src_clk = NULL;
- return -ENODEV;
- }
-
- pcm_branch_clk = clk_get(dai->dev, "ibit_clk");
-
- if (IS_ERR(pcm_branch_clk)) {
- pr_err("%s: could not get pcm_branch_clk\n", __func__);
- pcm_branch_clk = NULL;
- return -ENODEV;
- }
- }
-
- if ((!pcm_oe_src_clk) || (!pcm_oe_branch_clk)) {
-
- pcm_oe_src_clk = clk_get(dai->dev, "core_oe_src_clk");
-
- if (IS_ERR(pcm_oe_src_clk)) {
- pr_err("%s: could not get pcm_oe_src_clk\n", __func__);
- pcm_oe_src_clk = NULL;
- return -ENODEV;
- }
-
- pcm_oe_branch_clk = clk_get(dai->dev, "core_oe_clk");
- if (IS_ERR(pcm_oe_branch_clk)) {
- pr_err("%s: could not get pcm_oe_clk\n", __func__);
- pcm_oe_branch_clk = NULL;
- return -ENODEV;
- }
- }
- mutex_unlock(&aux_pcm_mutex);
dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
@@ -1107,6 +1082,7 @@
{
int rc = 0;
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
+ struct afe_clk_cfg *clk_cfg = NULL;
uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
@@ -1117,15 +1093,6 @@
return -ENOMEM;
}
- rc = of_property_read_string(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-clk",
- &auxpcm_pdata->clk);
- if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-clk missing in DT node\n",
- __func__);
- goto fail_free_plat;
- }
-
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,msm-cpudai-auxpcm-mode",
val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
@@ -1200,17 +1167,26 @@
auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
+ clk_cfg = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
+ if (clk_cfg == NULL) {
+ pr_err("%s: Failed to allocate memory for clk cfg\n", __func__);
+ goto fail_free_plat;
+ }
+ auxpcm_pdata->clk_cfg = clk_cfg;
+
platform_set_drvdata(pdev, auxpcm_pdata);
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
if (rc) {
dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
__func__, rc);
- goto fail_free_plat;
+ goto fail_free_plat1;
}
return rc;
+fail_free_plat1:
+ kfree(clk_cfg);
fail_free_plat:
kfree(auxpcm_pdata);
return rc;
@@ -1225,9 +1201,12 @@
static int __devexit msm_auxpcm_resource_remove(
struct platform_device *pdev)
{
- void *auxpcm_pdata;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata;
+ struct afe_clk_cfg *clk_cfg;
auxpcm_pdata = dev_get_drvdata(&pdev->dev);
+ clk_cfg = (struct afe_clk_cfg *)auxpcm_pdata->clk_cfg;
+ kfree(clk_cfg);
kfree(auxpcm_pdata);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-stub-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-stub-v2.c
new file mode 100644
index 0000000..7c1bdb6
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-dai-stub-v2.c
@@ -0,0 +1,115 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+static int msm_dai_stub_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ pr_debug("%s:\n", __func__);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops msm_dai_stub_ops = {
+ .set_channel_map = msm_dai_stub_set_channel_map,
+};
+
+static struct snd_soc_dai_driver msm_dai_stub_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_stub_ops,
+};
+
+static __devinit int msm_dai_stub_dev_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-dai-stub");
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_stub_dai);
+
+ return rc;
+}
+
+static __devexit int msm_dai_stub_dev_remove(struct platform_device *pdev)
+{
+ pr_debug("%s:\n", __func__);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id msm_dai_stub_dt_match[] = {
+ {.compatible = "qcom,msm-dai-stub"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_stub_dt_match);
+
+
+static struct platform_driver msm_dai_stub_driver = {
+ .probe = msm_dai_stub_dev_probe,
+ .remove = msm_dai_stub_dev_remove,
+ .driver = {
+ .name = "msm-dai-stub",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_dai_stub_dt_match,
+ },
+};
+
+static int __init msm_dai_stub_init(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ return platform_driver_register(&msm_dai_stub_driver);
+}
+module_init(msm_dai_stub_init);
+
+static void __exit msm_dai_stub_exit(void)
+{
+ pr_debug("%s:\n", __func__);
+
+ platform_driver_unregister(&msm_dai_stub_driver);
+}
+module_exit(msm_dai_stub_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Stub DSP DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-dtmf-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-dtmf-v2.c
new file mode 100644
index 0000000..3fdde7f
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-dtmf-v2.c
@@ -0,0 +1,598 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/q6afe-v2.h>
+
+#include "msm-pcm-q6-v2.h"
+#include "msm-pcm-routing-v2.h"
+#include "q6voice.h"
+
+enum {
+ DTMF_IN_RX,
+ DTMF_IN_TX,
+};
+
+enum format {
+ FORMAT_S16_LE = 2
+};
+
+struct dtmf_det_info {
+ char session[MAX_SESSION_NAME_LEN];
+ uint8_t dir;
+ uint16_t high_freq;
+ uint16_t low_freq;
+};
+
+struct dtmf_buf_node {
+ struct list_head list;
+ struct dtmf_det_info dtmf_det_pkt;
+};
+
+enum dtmf_state {
+ DTMF_GEN_RX_STOPPED,
+ DTMF_GEN_RX_STARTED,
+};
+
+#define DTMF_MAX_Q_LEN 10
+#define DTMF_PKT_SIZE sizeof(struct dtmf_det_info)
+
+struct dtmf_drv_info {
+ enum dtmf_state state;
+ struct snd_pcm_substream *capture_substream;
+
+ struct list_head out_queue;
+ struct list_head free_out_queue;
+
+ wait_queue_head_t out_wait;
+
+ struct mutex lock;
+ spinlock_t dsp_lock;
+
+ uint8_t capture_start;
+ uint8_t capture_instance;
+
+ unsigned int pcm_capture_size;
+ unsigned int pcm_capture_count;
+ unsigned int pcm_capture_irq_pos;
+ unsigned int pcm_capture_buf_pos;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = (sizeof(struct dtmf_buf_node) * DTMF_MAX_Q_LEN),
+ .period_bytes_min = DTMF_PKT_SIZE,
+ .period_bytes_max = DTMF_PKT_SIZE,
+ .periods_min = DTMF_MAX_Q_LEN,
+ .periods_max = DTMF_MAX_Q_LEN,
+ .fifo_size = 0,
+};
+
+static int msm_dtmf_rx_generate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint16_t low_freq = ucontrol->value.integer.value[0];
+ uint16_t high_freq = ucontrol->value.integer.value[1];
+ int64_t duration = ucontrol->value.integer.value[2];
+ uint16_t gain = ucontrol->value.integer.value[3];
+
+ pr_debug("%s: low_freq=%d high_freq=%d duration=%d gain=%d\n",
+ __func__, low_freq, high_freq, (int)duration, gain);
+ afe_dtmf_generate_rx(duration, high_freq, low_freq, gain);
+ return 0;
+}
+
+static int msm_dtmf_rx_generate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s:\n", __func__);
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_dtmf_detect_voice_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int enable = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: enable=%d\n", __func__, enable);
+ voc_enable_dtmf_rx_detection(voc_get_session_id(VOICE_SESSION_NAME),
+ enable);
+
+ return 0;
+}
+
+static int msm_dtmf_detect_voice_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_dtmf_detect_volte_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int enable = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: enable=%d\n", __func__, enable);
+ voc_enable_dtmf_rx_detection(voc_get_session_id(VOLTE_SESSION_NAME),
+ enable);
+
+ return 0;
+}
+
+static int msm_dtmf_detect_volte_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static struct snd_kcontrol_new msm_dtmf_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DTMF_Generate Rx Low High Duration Gain",
+ SND_SOC_NOPM, 0, 5000, 0, 4,
+ msm_dtmf_rx_generate_get,
+ msm_dtmf_rx_generate_put),
+ SOC_SINGLE_EXT("DTMF_Detect Rx Voice enable", SND_SOC_NOPM, 0, 1, 0,
+ msm_dtmf_detect_voice_rx_get,
+ msm_dtmf_detect_voice_rx_put),
+ SOC_SINGLE_EXT("DTMF_Detect Rx VoLTE enable", SND_SOC_NOPM, 0, 1, 0,
+ msm_dtmf_detect_volte_rx_get,
+ msm_dtmf_detect_volte_rx_put),
+};
+
+static int msm_pcm_dtmf_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_dtmf_controls,
+ ARRAY_SIZE(msm_dtmf_controls));
+ return 0;
+}
+
+static void dtmf_rx_detected_cb(uint8_t *pkt,
+ char *session,
+ void *private_data)
+{
+ struct dtmf_buf_node *buf_node = NULL;
+ struct vss_istream_evt_rx_dtmf_detected *dtmf_det_pkt =
+ (struct vss_istream_evt_rx_dtmf_detected *)pkt;
+ struct dtmf_drv_info *prtd = private_data;
+ unsigned long dsp_flags;
+
+ pr_debug("%s\n", __func__);
+ if (prtd->capture_substream == NULL)
+ return;
+
+ /* Copy dtmf detected info into out_queue. */
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ /* discarding dtmf detection info till start is received */
+ if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
+ buf_node = list_first_entry(&prtd->free_out_queue,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ buf_node->dtmf_det_pkt.high_freq = dtmf_det_pkt->high_freq;
+ buf_node->dtmf_det_pkt.low_freq = dtmf_det_pkt->low_freq;
+ if (session != NULL)
+ strlcpy(buf_node->dtmf_det_pkt.session,
+ session, MAX_SESSION_NAME_LEN);
+
+ buf_node->dtmf_det_pkt.dir = DTMF_IN_RX;
+ pr_debug("high =%d, low=%d session=%s\n",
+ buf_node->dtmf_det_pkt.high_freq,
+ buf_node->dtmf_det_pkt.low_freq,
+ buf_node->dtmf_det_pkt.session);
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+ prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ snd_pcm_period_elapsed(prtd->capture_substream);
+ } else {
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ pr_err("DTMF detection pkt in Rx dropped, no free node available\n");
+ }
+
+ wake_up(&prtd->out_wait);
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff,
+ void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int count = 0;
+ struct dtmf_buf_node *buf_node = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
+
+ count = frames_to_bytes(runtime, frames);
+
+ ret = wait_event_interruptible_timeout(prtd->out_wait,
+ (!list_empty(&prtd->out_queue)),
+ 1 * HZ);
+
+ if (ret > 0) {
+ if (count <= DTMF_PKT_SIZE) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ buf_node = list_first_entry(&prtd->out_queue,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+ ret = copy_to_user(buf,
+ &buf_node->dtmf_det_pkt,
+ count);
+ if (ret) {
+ pr_err("%s: Copy to user retuned %d\n",
+ __func__, ret);
+ ret = -EFAULT;
+ }
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ list_add_tail(&buf_node->list,
+ &prtd->free_out_queue);
+ spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+
+ } else {
+ pr_err("%s: Read count %d > DTMF_PKT_SIZE\n",
+ __func__, count);
+ ret = -ENOMEM;
+ }
+ } else if (ret == 0) {
+ pr_err("%s: No UL data available\n", __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ pr_err("%s: Read was interrupted\n", __func__);
+ ret = -ERESTARTSYS;
+ }
+ return ret;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ pr_debug("%s() DTMF\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = NULL;
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ prtd = kzalloc(sizeof(struct dtmf_drv_info), GFP_KERNEL);
+
+ if (prtd == NULL) {
+ pr_err("Failed to allocate memory for msm_audio\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mutex_init(&prtd->lock);
+ spin_lock_init(&prtd->dsp_lock);
+ init_waitqueue_head(&prtd->out_wait);
+ INIT_LIST_HEAD(&prtd->out_queue);
+ INIT_LIST_HEAD(&prtd->free_out_queue);
+
+ runtime->hw = msm_pcm_hardware;
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+ prtd->capture_substream = substream;
+ prtd->capture_instance++;
+ runtime->private_data = prtd;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct list_head *ptr = NULL;
+ struct list_head *next = NULL;
+ struct dtmf_buf_node *buf_node = NULL;
+ struct snd_dma_buffer *c_dma_buf;
+ struct snd_pcm_substream *c_substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+ unsigned long dsp_flags;
+
+ pr_debug("%s() DTMF\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mutex_lock(&prtd->lock);
+ wake_up(&prtd->out_wait);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_instance--;
+
+ if (!prtd->capture_instance) {
+ if (prtd->state == DTMF_GEN_RX_STARTED) {
+ prtd->state = DTMF_GEN_RX_STOPPED;
+ voc_disable_dtmf_det_on_active_sessions();
+ voc_register_dtmf_rx_detection_cb(NULL, NULL);
+ }
+ /* release all buffer */
+ /* release out_queue and free_out_queue */
+ pr_debug("release all buffer\n");
+ c_substream = prtd->capture_substream;
+ if (c_substream == NULL) {
+ pr_debug("c_substream is NULL\n");
+ mutex_unlock(&prtd->lock);
+ return -EINVAL;
+ }
+
+ c_dma_buf = &c_substream->dma_buffer;
+ if (c_dma_buf == NULL) {
+ pr_debug("c_dma_buf is NULL.\n");
+ mutex_unlock(&prtd->lock);
+ return -EINVAL;
+ }
+
+ if (c_dma_buf->area != NULL) {
+ spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+ list_for_each_safe(ptr, next,
+ &prtd->out_queue) {
+ buf_node = list_entry(ptr,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ list_for_each_safe(ptr, next,
+ &prtd->free_out_queue) {
+ buf_node = list_entry(ptr,
+ struct dtmf_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ spin_unlock_irqrestore(&prtd->dsp_lock,
+ dsp_flags);
+ dma_free_coherent(c_substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max,
+ c_dma_buf->area,
+ c_dma_buf->addr);
+ c_dma_buf->area = NULL;
+ }
+ }
+ prtd->capture_substream = NULL;
+ mutex_unlock(&prtd->lock);
+ }
+
+ return ret;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct dtmf_buf_node *buf_node = NULL;
+ int i = 0, offset = 0;
+ int ret = 0;
+
+ pr_debug("%s: DTMF\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mutex_lock(&prtd->lock);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+
+ dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+ runtime->hw.buffer_bytes_max,
+ &dma_buf->addr, GFP_KERNEL);
+ if (!dma_buf->area) {
+ pr_err("%s:MSM DTMF dma_alloc failed\n", __func__);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+
+ for (i = 0; i < DTMF_MAX_Q_LEN; i++) {
+ pr_debug("node =%d\n", i);
+ buf_node = (void *) dma_buf->area + offset;
+ list_add_tail(&buf_node->list,
+ &prtd->free_out_queue);
+ offset = offset + sizeof(struct dtmf_buf_node);
+ }
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ mutex_unlock(&prtd->lock);
+ }
+
+ return ret;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ pr_debug("%s: DTMF\n", __func__);
+ prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_capture_irq_pos = 0;
+ prtd->pcm_capture_buf_pos = 0;
+ return 0;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ pr_debug("%s: DTMF\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mutex_lock(&prtd->lock);
+
+ msm_pcm_capture_prepare(substream);
+
+ if (runtime->format != FORMAT_S16_LE) {
+ pr_err("format:%u doesnt match %d\n",
+ (uint32_t)runtime->format, FORMAT_S16_LE);
+ mutex_unlock(&prtd->lock);
+ return -EINVAL;
+ }
+
+ if (prtd->capture_instance &&
+ (prtd->state != DTMF_GEN_RX_STARTED)) {
+ voc_register_dtmf_rx_detection_cb(dtmf_rx_detected_cb,
+ prtd);
+ prtd->state = DTMF_GEN_RX_STARTED;
+ }
+ mutex_unlock(&prtd->lock);
+ }
+
+ return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ pr_debug("%s: Trigger start\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_start = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->capture_start = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ snd_pcm_uframes_t ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dtmf_drv_info *prtd = runtime->private_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
+ prtd->pcm_capture_irq_pos = 0;
+ ret = bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
+ }
+
+ return ret;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .copy = msm_pcm_copy,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+ .probe = msm_pcm_dtmf_probe,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-pcm-dtmf");
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_dtmf_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-dtmf"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_pcm_dtmf_dt_match);
+
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-dtmf",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_dtmf_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("DTMF platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 1d6e106..fa8609e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -40,6 +40,12 @@
struct snd_pcm *pcm;
};
+struct snd_msm_volume {
+ struct msm_audio *prtd;
+ unsigned volume;
+};
+static struct snd_msm_volume pcm_audio = {NULL, 0x2000};
+
#define PLAYBACK_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 12288
#define PLAYBACK_MIN_PERIOD_SIZE 2048
@@ -213,8 +219,11 @@
if (prtd->enabled)
return 0;
- ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
- runtime->channels);
+ ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
+ runtime->rate,
+ runtime->channels,
+ !prtd->set_channel_map,
+ prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -365,7 +374,9 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
+ pcm_audio.prtd = prtd;
return 0;
}
@@ -449,7 +460,8 @@
prtd->audio_client);
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_PLAYBACK);
+ SNDRV_PCM_STREAM_PLAYBACK);
+ pcm_audio.prtd = NULL;
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
@@ -691,13 +703,49 @@
.mmap = msm_pcm_mmap,
};
+static int pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ pr_debug("%s", __func__);
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+ if (pcm_audio.prtd) {
+ pcm_audio.prtd->set_channel_map = true;
+ memcpy(pcm_audio.prtd->channel_map, channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+ return 0;
+}
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_chmap *chmap_info;
+ struct snd_kcontrol *kctl;
+ char device_num[3];
+ int i, ret = 0;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ pr_debug("%s, Channel map cntrl add\n", __func__);
+ ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ &chmap_info);
+ if (ret < 0)
+ return ret;
+ kctl = chmap_info->kctl;
+ for (i = 0; i < kctl->count; i++)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ snprintf(device_num, sizeof(device_num), "%d", pcm->device);
+ strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
+ pr_debug("%s, Overwriting channel map control name to: %s",
+ __func__, kctl->id.name);
+ kctl->put = pcm_chmap_ctl_put;
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index e25d356..9a770bf 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2012 Code Aurora Forum. 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
@@ -82,6 +82,8 @@
int periods;
int mmap_flag;
atomic_t pending_buffer;
+ bool set_channel_map;
+ char channel_map[8];
};
struct output_meta_data_st {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 26f634b..ad6d5e8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -525,6 +525,13 @@
else
clear_bit(val, &msm_bedais[reg].fe_sessions);
+ if (val == MSM_FRONTEND_DAI_DTMF_RX &&
+ afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX) {
+ pr_debug("%s(): set=%d port id=0x%x for dtmf generation\n",
+ __func__, set, msm_bedais[reg].port_id);
+ afe_set_dtmf_gen_rx_portid(msm_bedais[reg].port_id, set);
+ }
mutex_unlock(&routing_lock);
if (afe_get_port_type(msm_bedais[reg].port_id) ==
@@ -805,6 +812,31 @@
return 0;
}
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+ int i;
+
+ adm_get_multi_ch_map(channel_map);
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = (unsigned) channel_map[i];
+ return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+ int i;
+
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_map[i] = (char)(ucontrol->value.integer.value[i]);
+ adm_set_multi_ch_map(channel_map);
+
+ return 0;
+}
+
static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1277,6 +1309,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1289,6 +1324,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1301,6 +1339,9 @@
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),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1316,6 +1357,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -1328,6 +1372,12 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_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_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -1343,6 +1393,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -1358,6 +1411,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -1373,6 +1429,9 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -1430,6 +1489,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_VoLTE", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
@@ -1577,6 +1639,12 @@
msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
};
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 16,
+ 0, 8, msm_routing_get_channel_map_mixer,
+ msm_routing_put_channel_map_mixer),
+};
+
static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SRS TruMedia",
@@ -1860,7 +1928,8 @@
SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
-
+ SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
+ 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
*/
@@ -2142,42 +2211,61 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
+ {"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"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"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"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", NULL, "AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
{"HDMI", NULL, "HDMI_DL_HL"},
+ {"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
@@ -2190,6 +2278,7 @@
{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
{"VoLTE_Tx Mixer", "AFE_PCM_TX_VoLTE", "PCM_TX"},
{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "MI2S_TX_VoLTE", "MI2S_TX"},
{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
@@ -2245,12 +2334,6 @@
{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
- {"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
- {"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
- {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
- {"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
- {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
-
{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
@@ -2491,6 +2574,10 @@
snd_soc_add_platform_controls(platform,
lpa_SRS_trumedia_controls_I2S,
ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
+
+ snd_soc_add_platform_controls(platform,
+ multi_ch_channel_map_mixer_controls,
+ ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 69b3fe3..443e461 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -64,6 +64,7 @@
MSM_FRONTEND_DAI_AFE_TX,
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
+ MSM_FRONTEND_DAI_DTMF_RX,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 660e6a8..bc11304 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -52,6 +52,15 @@
static struct adm_ctl this_adm;
+struct adm_multi_ch_map {
+ bool set_channel_map;
+ char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+};
+
+static struct adm_multi_ch_map multi_ch_map = { false,
+ {0, 0, 0, 0, 0, 0, 0, 0}
+ };
+
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
{
struct adm_cmd_set_pp_params_inband_v5 *adm_params = NULL;
@@ -266,6 +275,21 @@
__func__, data->opcode, data->payload_size);
}
+void adm_set_multi_ch_map(char *channel_map)
+{
+ memcpy(multi_ch_map.channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ multi_ch_map.set_channel_map = true;
+}
+
+void adm_get_multi_ch_map(char *channel_map)
+{
+ if (multi_ch_map.set_channel_map) {
+ memcpy(channel_map, multi_ch_map.channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+}
+
static int32_t adm_callback(struct apr_client_data *data, void *priv)
{
uint32_t *payload;
@@ -743,6 +767,11 @@
channel_mode);
return -EINVAL;
}
+ if ((open.dev_num_channel > 2) &&
+ multi_ch_map.set_channel_map)
+ memcpy(open.dev_channel_mapping,
+ multi_ch_map.channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
pr_debug("%s: port_id=%#x rate=%d topology_id=0x%X\n",
__func__, open.endpoint_id_1, open.sample_rate,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 846c80e..050a2719 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -43,6 +43,7 @@
struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
atomic_t mem_map_cal_index;
+ u16 dtmf_gen_rx_portid;
};
static struct afe_ctl this_afe;
@@ -95,6 +96,7 @@
case AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS:
case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
+ case AFE_PORTS_CMD_DTMF_CTL:
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
break;
@@ -1802,6 +1804,84 @@
return;
}
#endif
+
+void afe_set_dtmf_gen_rx_portid(u16 port_id, int set)
+{
+ if (set)
+ this_afe.dtmf_gen_rx_portid = port_id;
+ else if (this_afe.dtmf_gen_rx_portid == port_id)
+ this_afe.dtmf_gen_rx_portid = -1;
+}
+
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+ uint16_t high_freq,
+ uint16_t low_freq, uint16_t gain)
+{
+ int ret = 0;
+ int index = 0;
+ struct afe_dtmf_generation_command cmd_dtmf;
+
+ pr_debug("%s: DTMF AFE Gen\n", __func__);
+
+ if (afe_validate_port(this_afe.dtmf_gen_rx_portid) < 0) {
+ pr_err("%s: Failed : Invalid Port id = %d\n",
+ __func__, this_afe.dtmf_gen_rx_portid);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ pr_debug("dur=%lld: hfreq=%d lfreq=%d gain=%d portid=%x\n",
+ duration_in_ms, high_freq, low_freq, gain,
+ this_afe.dtmf_gen_rx_portid);
+
+ cmd_dtmf.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd_dtmf.hdr.pkt_size = sizeof(cmd_dtmf);
+ cmd_dtmf.hdr.src_port = 0;
+ cmd_dtmf.hdr.dest_port = 0;
+ cmd_dtmf.hdr.token = 0;
+ cmd_dtmf.hdr.opcode = AFE_PORTS_CMD_DTMF_CTL;
+ cmd_dtmf.duration_in_ms = duration_in_ms;
+ cmd_dtmf.high_freq = high_freq;
+ cmd_dtmf.low_freq = low_freq;
+ cmd_dtmf.gain = gain;
+ cmd_dtmf.num_ports = 1;
+ cmd_dtmf.port_ids = q6audio_get_port_id(this_afe.dtmf_gen_rx_portid);
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_dtmf);
+ if (ret < 0) {
+ pr_err("%s: AFE DTMF failed for num_ports:%d ids:%x\n",
+ __func__, cmd_dtmf.num_ports, cmd_dtmf.port_ids);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(this_afe.dtmf_gen_rx_portid);
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret < 0) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ return 0;
+
+fail_cmd:
+ return ret;
+}
+
int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
{
struct afe_loopback_cfg_v1 cmd_sidetone;
@@ -2195,6 +2275,7 @@
atomic_set(&this_afe.status, 0);
atomic_set(&this_afe.mem_map_cal_index, -1);
this_afe.apr = NULL;
+ this_afe.dtmf_gen_rx_portid = -1;
this_afe.mmap_handle = 0;
for (i = 0; i < AFE_MAX_PORTS; i++)
init_waitqueue_head(&this_afe.wait[i]);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 8d579c6..29c38e7 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -80,7 +80,8 @@
static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
uint32_t pkt_size, uint32_t cmd_flg);
static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
- uint32_t bufsz, uint32_t bufcnt);
+ uint32_t bufsz, uint32_t bufcnt,
+ bool is_contiguous);
static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
uint32_t bufsz, uint32_t bufcnt);
static void q6asm_reset_buf_state(struct audio_client *ac);
@@ -681,7 +682,7 @@
ac->port[dir].max_buf_cnt = cnt;
mutex_unlock(&ac->cmd_lock);
- rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+ rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 0);
if (rc < 0) {
pr_err("%s:CMD Memory_map_regions failed\n", __func__);
goto fail;
@@ -787,7 +788,7 @@
}
ac->port[dir].max_buf_cnt = cnt;
mutex_unlock(&ac->cmd_lock);
- rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+ rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 1);
if (rc < 0) {
pr_err("%s:CMD Memory_map_regions failed\n", __func__);
goto fail;
@@ -839,6 +840,11 @@
switch (payload[0]) {
case ASM_CMD_SHARED_MEM_MAP_REGIONS:
case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+ if (payload[1] != 0) {
+ pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
+ __func__, payload[0], payload[1], sid);
+ }
+
if (atomic_read(&ac->cmd_state)) {
atomic_set(&ac->cmd_state, 0);
wake_up(&ac->cmd_wait);
@@ -949,6 +955,7 @@
ac->cb(data->opcode, data->token,
(uint32_t *)data->payload, ac->priv);
apr_reset(ac->apr);
+ ac->apr = NULL;
return 0;
}
@@ -1851,12 +1858,12 @@
lchannel_mapping[3] = PCM_CHANNEL_LB;
lchannel_mapping[4] = PCM_CHANNEL_RB;
} else if (channels == 6) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LB;
+ lchannel_mapping[4] = PCM_CHANNEL_RB;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
@@ -2166,6 +2173,56 @@
return -EINVAL;
}
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map)
+{
+ struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
+ u8 *channel_mapping;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+ channels);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.num_channels = channels;
+ fmt.bits_per_sample = 16;
+ fmt.sample_rate = rate;
+ fmt.is_signed = 1;
+
+ channel_mapping = fmt.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels)) {
+ pr_err("%s: map channels failed", __func__);
+ return -EINVAL;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for format update\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg)
{
@@ -2441,7 +2498,8 @@
static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
- uint32_t bufsz, uint32_t bufcnt)
+ uint32_t bufsz, uint32_t bufcnt,
+ bool is_contiguous)
{
struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
struct avs_shared_map_region_payload *mregions = NULL;
@@ -2453,6 +2511,8 @@
int rc = 0;
int i = 0;
int cmd_size = 0;
+ uint32_t bufcnt_t;
+ uint32_t bufsz_t;
if (!ac || ac->apr == NULL || ac->mmap_apr == NULL) {
pr_err("APR handle NULL\n");
@@ -2460,8 +2520,12 @@
}
pr_debug("%s: Session[%d]\n", __func__, ac->session);
+ bufcnt_t = (is_contiguous) ? 1 : bufcnt;
+ bufsz_t = (is_contiguous) ? (bufsz * bufcnt) : bufsz;
+
cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
- + (sizeof(struct avs_shared_map_region_payload));
+ + (sizeof(struct avs_shared_map_region_payload)
+ * bufcnt_t);
buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
GFP_KERNEL);
@@ -2481,7 +2545,7 @@
mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
- mmap_regions->num_regions = 1; /*bufcnt & 0x00ff; */
+ mmap_regions->num_regions = bufcnt_t; /*bufcnt & 0x00ff; */
mmap_regions->property_flag = 0x00;
pr_debug("map_regions->nregions = %d\n", mmap_regions->num_regions);
payload = ((u8 *) mmap_region_cmd +
@@ -2490,11 +2554,14 @@
ac->port[dir].tmp_hdl = 0;
port = &ac->port[dir];
- ab = &port->buf[0];
- mregions->shm_addr_lsw = ab->phys;
+ for (i = 0; i < bufcnt_t; i++) {
+ ab = &port->buf[i];
+ mregions->shm_addr_lsw = ab->phys;
/* Using only 32 bit address */
- mregions->shm_addr_msw = 0;
- mregions->mem_size_bytes = (bufsz * bufcnt);
+ mregions->shm_addr_msw = 0;
+ mregions->mem_size_bytes = bufsz_t;
+ ++mregions;
+ }
rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
if (rc < 0) {
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 63741ec..03e4769 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -158,6 +158,21 @@
v->cvp_handle = cvp_handle;
}
+char *voc_get_session_name(u16 session_id)
+{
+ char *session_name = NULL;
+
+ if (session_id == common.voice[VOC_PATH_PASSIVE].session_id) {
+ session_name = VOICE_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_VOLTE_PASSIVE].session_id) {
+ session_name = VOLTE_SESSION_NAME;
+ } else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
+ session_name = VOIP_SESSION_NAME;
+ }
+ return session_name;
+}
+
uint16_t voc_get_session_id(char *name)
{
u16 session_id = 0;
@@ -1023,6 +1038,106 @@
fail:
return -EINVAL;
}
+
+static int voice_send_dtmf_rx_detection_cmd(struct voice_data *v,
+ uint32_t enable)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_rx_dtmf_detection_cmd cvs_dtmf_rx_detection;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* Set SET_DTMF_RX_DETECTION */
+ cvs_dtmf_rx_detection.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ 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.dest_port = cvs_handle;
+ cvs_dtmf_rx_detection.hdr.token = 0;
+ cvs_dtmf_rx_detection.hdr.opcode =
+ VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION;
+ cvs_dtmf_rx_detection.cvs_dtmf_det.enable = enable;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_dtmf_rx_detection);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTMF_RX_DETECTION\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+void voc_disable_dtmf_det_on_active_sessions(void)
+{
+ struct voice_data *v = NULL;
+ int i;
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ v = &common.voice[i];
+ if ((v->dtmf_rx_detect_en) &&
+ ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))) {
+ pr_debug("disable dtmf det on ses_id=%d\n",
+ v->session_id);
+ voice_send_dtmf_rx_detection_cmd(v, 0);
+ }
+ }
+}
+
+int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+ v->dtmf_rx_detect_en = enable;
+
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
+ ret = voice_send_dtmf_rx_detection_cmd(v,
+ v->dtmf_rx_detect_en);
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -2218,6 +2333,9 @@
if (v->rec_info.rec_enable)
voice_cvs_start_record(v, v->rec_info.rec_mode);
+ if (v->dtmf_rx_detect_en)
+ voice_send_dtmf_rx_detection_cmd(v, v->dtmf_rx_detect_en);
+
rtac_add_voice(voice_get_cvs_handle(v),
voice_get_cvp_handle(v),
v->dev_rx.port_id, v->dev_tx.port_id,
@@ -2511,6 +2629,10 @@
/* send stop voice cmd */
voice_send_stop_voice_cmd(v);
+ /* send stop dtmf detecton cmd */
+ if (v->dtmf_rx_detect_en)
+ voice_send_dtmf_rx_detection_cmd(v, 0);
+
/* detach VOCPROC and wait for response from mvm */
mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -3936,6 +4058,13 @@
common.mvs_info.private_data = private_data;
}
+void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
+ void *private_data)
+{
+ common.dtmf_info.dtmf_rx_ul_cb = dtmf_rx_ul_cb;
+ common.dtmf_info.private_data = private_data;
+}
+
void voc_config_vocoder(uint32_t media_type,
uint32_t rate,
uint32_t network_type,
@@ -4005,7 +4134,7 @@
if (data->payload_size) {
ptr = data->payload;
- pr_info("%x %x\n", ptr[0], ptr[1]);
+ pr_debug("%x %x\n", ptr[0], ptr[1]);
/* ping mvm service ACK */
switch (ptr[0]) {
case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -4137,7 +4266,7 @@
if (data->payload_size) {
ptr = data->payload;
- pr_info("%x %x\n", ptr[0], ptr[1]);
+ pr_debug("%x %x\n", ptr[0], ptr[1]);
if (ptr[1] != 0) {
pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
__func__, ptr[0], ptr[1]);
@@ -4173,6 +4302,7 @@
case VSS_IRECORD_CMD_STOP:
case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
+ case VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->cvs_state = CMD_STATUS_SUCCESS;
wake_up(&v->cvs_wait);
@@ -4320,8 +4450,29 @@
}
rtac_make_voice_callback(RTAC_CVS, data->payload,
data->payload_size);
+ } else if (data->opcode == VSS_ISTREAM_EVT_RX_DTMF_DETECTED) {
+ struct vss_istream_evt_rx_dtmf_detected *dtmf_rx_detected;
+ uint32_t *voc_pkt = data->payload;
+ uint32_t pkt_len = data->payload_size;
+
+ if ((voc_pkt != NULL) &&
+ (pkt_len ==
+ sizeof(struct vss_istream_evt_rx_dtmf_detected))) {
+
+ dtmf_rx_detected =
+ (struct vss_istream_evt_rx_dtmf_detected *) voc_pkt;
+ pr_debug("RX_DTMF_DETECTED low_freq=%d high_freq=%d\n",
+ dtmf_rx_detected->low_freq,
+ dtmf_rx_detected->high_freq);
+ if (c->dtmf_info.dtmf_rx_ul_cb)
+ c->dtmf_info.dtmf_rx_ul_cb((uint8_t *)voc_pkt,
+ voc_get_session_name(v->session_id),
+ c->dtmf_info.private_data);
+ } else {
+ pr_err("Invalid packet\n");
+ }
} else
- pr_err("Unknown opcode 0x%x\n", data->opcode);
+ pr_debug("Unknown opcode 0x%x\n", data->opcode);
fail:
return 0;
@@ -4380,7 +4531,7 @@
if (data->payload_size) {
ptr = data->payload;
- pr_info("%x %x\n", ptr[0], ptr[1]);
+ pr_debug("%x %x\n", ptr[0], ptr[1]);
if (ptr[1] != 0) {
pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
__func__, ptr[0], ptr[1]);
@@ -4681,6 +4832,7 @@
common.voice[i].dev_tx.port_id = 0x100B;
common.voice[i].dev_rx.port_id = 0x100A;
common.voice[i].sidetone_gain = 0x512;
+ common.voice[i].dtmf_rx_detect_en = 0;
common.voice[i].voc_state = VOC_INIT;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index d19697a..9f77af6 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.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
@@ -741,6 +741,56 @@
/* Reserved, set to 0. */
};
+/*
+ * Event sent by the stream to the client that enables Rx DTMF
+ * detection whenever DTMF is detected in the Rx path.
+ *
+ * The DTMF detection feature can only be used to detect DTMF
+ * frequencies as listed in the vss_istream_evt_rx_dtmf_detected_t
+ * structure.
+ */
+
+#define VSS_ISTREAM_EVT_RX_DTMF_DETECTED (0x0001101A)
+
+struct vss_istream_cmd_set_rx_dtmf_detection {
+ /*
+ * Enables/disables Rx DTMF detection
+ *
+ * Possible values are
+ * 0 - disable
+ * 1 - enable
+ *
+ */
+ uint32_t enable;
+};
+
+#define VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION (0x00011027)
+
+struct vss_istream_evt_rx_dtmf_detected {
+ uint16_t low_freq;
+ /*
+ * Detected low frequency. Possible values:
+ * 697 Hz
+ * 770 Hz
+ * 852 Hz
+ * 941 Hz
+ */
+ uint16_t high_freq;
+ /*
+ * Detected high frequency. Possible values:
+ * 1209 Hz
+ * 1336 Hz
+ * 1477 Hz
+ * 1633 Hz
+ */
+};
+
+struct cvs_set_rx_dtmf_detection_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_rx_dtmf_detection cvs_dtmf_det;
+} __packed;
+
+
struct cvs_create_passive_ctl_session_cmd {
struct apr_hdr hdr;
struct vss_istream_cmd_create_passive_control_session_t cvs_session;
@@ -1114,6 +1164,10 @@
typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
void *private_data);
+/* CB for DTMF RX Detection */
+typedef void (*dtmf_rx_det_cb_fn)(uint8_t *pkt,
+ char *session,
+ void *private_data);
struct mvs_driver_info {
uint32_t media_type;
@@ -1125,6 +1179,11 @@
void *private_data;
};
+struct dtmf_driver_info {
+ dtmf_rx_det_cb_fn dtmf_rx_ul_cb;
+ void *private_data;
+};
+
struct incall_rec_info {
uint32_t rec_enable;
uint32_t rec_mode;
@@ -1180,6 +1239,8 @@
/* FENC enable value */
uint32_t fens_enable;
+ uint32_t dtmf_rx_detect_en;
+
struct voice_dev_route_state voc_route_state;
u16 session_id;
@@ -1222,6 +1283,8 @@
struct mvs_driver_info mvs_info;
+ struct dtmf_driver_info dtmf_info;
+
struct voice_data voice[MAX_VOC_SESSIONS];
};
@@ -1229,6 +1292,9 @@
dl_cb_fn dl_cb,
void *private_data);
+void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
+ void *private_data);
+
void voc_config_vocoder(uint32_t media_type,
uint32_t rate,
uint32_t network_type,
@@ -1267,7 +1333,10 @@
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);
+void voc_disable_dtmf_det_on_active_sessions(void);
+#define MAX_SESSION_NAME_LEN 32
#define VOICE_SESSION_NAME "Voice session"
#define VOIP_SESSION_NAME "VoIP session"
#define VOLTE_SESSION_NAME "VoLTE session"
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5ac6434..99047178 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -78,7 +78,7 @@
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_aif_in] = 1,
[snd_soc_dapm_aif_out] = 1,
- [snd_soc_dapm_adc] = 1,
+ [snd_soc_dapm_adc] = 5,
[snd_soc_dapm_hp] = 2,
[snd_soc_dapm_spk] = 2,
[snd_soc_dapm_out_drv] = 2,
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 1452312..deeb5c7 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -723,7 +723,7 @@
return -EINVAL;
}
- usbaudiosdev = kzalloc(sizeof(usbaudiosdev), GFP_KERNEL);
+ usbaudiosdev = kzalloc(sizeof(*usbaudiosdev), GFP_KERNEL);
usbaudiosdev->name = "usb_audio";
err = switch_dev_register(usbaudiosdev);