Merge "msm: vidc: add HEVC kernel definitions"
diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
index 23d78b5..40f98a9 100644
--- a/Documentation/ABI/testing/sysfs-class-devfreq
+++ b/Documentation/ABI/testing/sysfs-class-devfreq
@@ -19,15 +19,16 @@
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description:
The /sys/class/devfreq/.../cur_freq shows the current
- frequency of the corresponding devfreq object.
+ frequency of the corresponding devfreq object. Same as
+ target_freq when get_cur_freq() is not implemented by
+ devfreq driver.
-What: /sys/class/devfreq/.../central_polling
-Date: September 2011
-Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+What: /sys/class/devfreq/.../target_freq
+Date: September 2012
+Contact: Rajagopal Venkat <rajagopal.venkat@linaro.org>
Description:
- The /sys/class/devfreq/.../central_polling shows whether
- the devfreq ojbect is using devfreq-provided central
- polling mechanism or not.
+ The /sys/class/devfreq/.../target_freq shows the next governor
+ predicted target frequency of the corresponding devfreq object.
What: /sys/class/devfreq/.../polling_interval
Date: September 2011
@@ -43,6 +44,17 @@
(/sys/class/devfreq/.../central_polling is 0), this value
may be useless.
+What: /sys/class/devfreq/.../trans_stat
+Date: October 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Descrtiption:
+ This ABI shows the statistics of devfreq behavior on a
+ specific device. It shows the time spent in each state and
+ the number of transitions between states.
+ In order to activate this ABI, the devfreq target device
+ driver should provide the list of available frequencies
+ with its profile.
+
What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
@@ -50,3 +62,12 @@
The /sys/class/devfreq/.../userspace/set_freq shows and
sets the requested frequency for the devfreq object if
userspace governor is in effect.
+
+What: /sys/class/devfreq/.../available_frequencies
+Date: October 2012
+Contact: Nishanth Menon <nm@ti.com>
+Description:
+ The /sys/class/devfreq/.../available_frequencies shows
+ the available frequencies of the corresponding devfreq object.
+ This is a snapshot of available frequencies and not limited
+ by the min/max frequency restrictions.
diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt
new file mode 100644
index 0000000..95f0fa4
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt
@@ -0,0 +1,37 @@
+Qualcomm mdss-qpic-panel
+
+mdss-qpic-panel is a panel device which can be driven by qpic.
+
+Required properties:
+- compatible: Must be "qcom,mdss-qpic-panel"
+- qcom,mdss-pan-res: A two dimensional array that specifies the panel
+ resolution.
+- qcom,mdss-pan-bpp: Specifies the panel bits per pixel.
+- qcom,refresh_rate: Panel refresh rate
+- vdd-supply: Phandle for vdd regulator device node.
+- avdd-supply: Phandle for avdd regulator device node.
+- qcom,cs-gpio: Phandle for cs gpio device node.
+- qcom,te-gpio: Phandle for te gpio device node.
+- qcom,rst-gpio: Phandle for rst gpio device node.
+- qcom,ad8-gpio: Phandle for ad8 gpio device node.
+
+Optional properties:
+- label: A string used as a descriptive name of the panel
+
+
+Example:
+/ {
+ qcom,mdss_lcdc_ili9341_qvga {
+ compatible = "qcom,mdss-qpic-panel";
+ label = "ili qvga lcdc panel";
+ vdd-supply = <&pm8019_l11>;
+ avdd-supply = <&pm8019_l14>;
+ qcom,cs-gpio = <&msmgpio 21 0>;
+ qcom,te-gpio = <&msmgpio 22 0>;
+ qcom,rst-gpio = <&msmgpio 23 0>;
+ qcom,ad8-gpio = <&msmgpio 20 0>;
+ qcom,mdss-pan-res = <240 320>;
+ qcom,mdss-pan-bpp = <18>;
+ qcom,refresh_rate = <60>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic.txt b/Documentation/devicetree/bindings/fb/mdss-qpic.txt
new file mode 100644
index 0000000..0fa3a32
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-qpic.txt
@@ -0,0 +1,18 @@
+Qualcomm mdss-qpic
+
+mdss-qpic is a qpic controller device which supports dma transmission to MIPI
+and LCDC panel.
+
+Required properties:
+- compatible: must be "qcom,mdss_qpic"
+- reg: offset and length of the register set for the device.
+- reg-names : names to refer to register sets related to this device
+- interrupts: IRQ line
+
+Example:
+ qcom,msm_qpic@f9ac0000 {
+ compatible = "qcom,mdss_qpic";
+ reg = <0xf9ac0000 0x24000>;
+ reg-names = "qpic_base";
+ interrupts = <0 251 0>;
+ };
diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
new file mode 100644
index 0000000..74499e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/opp.txt
@@ -0,0 +1,25 @@
+* Generic OPP Interface
+
+SoCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. These
+are called Operating Performance Points or OPPs.
+
+Properties:
+- operating-points: An array of 2-tuples items, and each item consists
+ of frequency and voltage like <freq-kHz vol-uV>.
+ freq: clock frequency in kHz
+ vol: voltage in microvolt
+
+Examples:
+
+cpu@0 {
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ operating-points = <
+ /* kHz uV */
+ 792000 1100000
+ 396000 950000
+ 198000 850000
+ >;
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index c488ab1..ec42cfc 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -95,5 +95,225 @@
reg = <0x1>;
#address-cells = <1>;
#size-cells = <1>;
+
+ regulator@1400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s1";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1400 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1400 {
+ reg = <0x1400 0x100>;
+ };
+ qcom,ps@1500 {
+ reg = <0x1500 0x100>;
+ };
+ qcom,freq@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
+
+ regulator@1700 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s2";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1700 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1700 {
+ reg = <0x1700 0x100>;
+ };
+ qcom,ps@1800 {
+ reg = <0x1800 0x100>;
+ };
+ qcom,freq@1900 {
+ reg = <0x1900 0x100>;
+ };
+ };
+
+ regulator@1a00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s3";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1a00 {
+ reg = <0x1a00 0x100>;
+ };
+ qcom,ps@1b00 {
+ reg = <0x1b00 0x100>;
+ };
+ qcom,freq@1c00 {
+ reg = <0x1c00 0x100>;
+ };
+ };
+
+ regulator@1d00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s4";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1d00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1d00 {
+ reg = <0x1d00 0x100>;
+ };
+ qcom,ps@1e00 {
+ reg = <0x1e00 0x100>;
+ };
+ qcom,freq@1f00 {
+ reg = <0x1f00 0x100>;
+ };
+ };
+
+ regulator@4000 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l1";
+ reg = <0x4000 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4100 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l2";
+ reg = <0x4100 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4200 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l3";
+ reg = <0x4200 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4300 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l4";
+ reg = <0x4300 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l5";
+ reg = <0x4400 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4500 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l6";
+ reg = <0x4500 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4600 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l7";
+ reg = <0x4600 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4700 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l8";
+ reg = <0x4700 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4800 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l9";
+ reg = <0x4800 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4900 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l10";
+ reg = <0x4900 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4b00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l12";
+ reg = <0x4b00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4d00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l14";
+ reg = <0x4d00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4e00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l15";
+ reg = <0x4e00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4f00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l16";
+ reg = <0x4f00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5000 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l17";
+ reg = <0x5000 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5100 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l18";
+ reg = <0x5100 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5200 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l19";
+ reg = <0x5200 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5300 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l20";
+ reg = <0x5300 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l21";
+ reg = <0x5400 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5500 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l22";
+ reg = <0x5500 0x100>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index fa77c35..800cd8f 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -90,6 +90,7 @@
sound {
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
};
};
@@ -193,6 +194,13 @@
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@c200 { /* GPIO 3 */
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index e747cb5..3d1fe19 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -90,6 +90,7 @@
sound {
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
};
};
@@ -190,6 +191,13 @@
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@c200 { /* GPIO 3 */
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index acc4597..4fa37d6 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -90,6 +90,7 @@
sound {
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
};
};
@@ -193,6 +194,13 @@
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@c200 { /* GPIO 3 */
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 0bc8efd..2ff8c8e 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -231,6 +231,8 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
"LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
"AMIC1", "MIC BIAS1 Internal1",
"MIC BIAS1 Internal1", "Handset Mic",
"AMIC2", "MIC BIAS2 External",
@@ -723,6 +725,12 @@
<0xfc336000 0x1000>;
reg-names = "etm-base","debug-base";
};
+
+ qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 362d126..f11f04b 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -12,216 +12,215 @@
/* Stub Regulators */
- / {
- pm8110_s1: regulator-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s1";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
-
+/ {
pm8110_s1_corner: regulator-s1-corner {
compatible = "qcom,stub-regulator";
regulator-name = "8110_s1_corner";
+ qcom,hpm-min-load = <100000>;
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,consumer-supplies = "vdd_dig", "";
};
+};
- pm8110_s2: regulator-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s2";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- };
+/* QPNP controlled regulators: */
- pm8110_s3: regulator-s3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s3";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- };
+&spmi_bus {
- pm8110_s4: regulator-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <2150000>;
- regulator-max-microvolt = <2150000>;
- };
+ qcom,pm8110@1 {
- pm8110_l1: regulator-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l1";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- };
+ pm8110_s1: regulator@1400 {
+ status = "okay";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l2: regulator-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l2";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8110_s2: regulator@1700 {
+ status = "okay";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l3: regulator-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l3";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
+ pm8110_s3: regulator@1a00 {
+ status = "okay";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l4: regulator-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l4";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8110_s4: regulator@1d00 {
+ status = "okay";
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l5: regulator-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l5";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- };
+ pm8110_l1: regulator@4000 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l6: regulator-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l6";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8110_l2: regulator@4100 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ };
- pm8110_l7: regulator-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l7";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8110_l3: regulator@4200 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ };
- pm8110_l8: regulator-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l8";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8110_l4: regulator@4300 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l9: regulator-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l9";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8110_l5: regulator@4400 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l10: regulator-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l10";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,consumer-supplies = "vdd_sr2_pll", "";
- };
+ pm8110_l6: regulator@4500 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ };
- pm8110_l12: regulator-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l12";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- };
+ pm8110_l7: regulator@4600 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l14: regulator-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l14";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8110_l8: regulator@4700 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l15: regulator-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- };
+ pm8110_l9: regulator@4800 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l16: regulator-l16 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l16";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
+ pm8110_l10: regulator@4900 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,consumer-supplies = "vdd_sr2_pll", "";
+ };
- pm8110_l17: regulator-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- };
+ pm8110_l12: regulator@4b00 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l18: regulator-l18 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l18";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8110_l14: regulator@4d00 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l19: regulator-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- };
+ pm8110_l15: regulator@4e00 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l20: regulator-l20 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l20";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- };
+ pm8110_l16: regulator@4f00 {
+ status = "okay";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l21: regulator-l21 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l21";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8110_l17: regulator@5000 {
+ status = "okay";
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l22: regulator-l22 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l22";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
+ pm8110_l18: regulator@5100 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l19: regulator@5200 {
+ status = "okay";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l20: regulator@5300 {
+ status = "okay";
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l21: regulator@5400 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l22: regulator@5500 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,enable-time = <200>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index b78c3af..6aa87ce 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -487,8 +487,8 @@
/include/ "msm8610-iommu-domains.dtsi"
-/include/ "msm8610-regulator.dtsi"
/include/ "msm-pm8110.dtsi"
+/include/ "msm8610-regulator.dtsi"
&pm8110_vadc {
chan@0 {
diff --git a/arch/arm/boot/dts/msm9625-display.dtsi b/arch/arm/boot/dts/msm9625-display.dtsi
new file mode 100644
index 0000000..a160bae
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-display.dtsi
@@ -0,0 +1,20 @@
+/* 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,msm_qpic@f9ac0000 {
+ compatible = "qcom,mdss_qpic";
+ reg = <0xf9ac0000 0x24000>;
+ reg-names = "qpic_base";
+ interrupts = <0 251 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
index 09a89ab..919c6d5 100644
--- a/arch/arm/boot/dts/msm9625-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -13,6 +13,8 @@
/dts-v1/;
/include/ "msm9625-v2.dtsi"
+/include/ "msm9625-display.dtsi"
+/include/ "qpic-panel-ili-qvga.dtsi"
/ {
model = "Qualcomm MSM 9625V2 CDP";
diff --git a/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
new file mode 100644
index 0000000..a0c906e
--- /dev/null
+++ b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
@@ -0,0 +1,27 @@
+/* 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,mdss_lcdc_ili9341_qvga {
+ compatible = "qcom,mdss-qpic-panel";
+ label = "ili qvga lcdc panel";
+ vdd-supply = <&pm8019_l11>;
+ avdd-supply = <&pm8019_l14>;
+ qcom,cs-gpio = <&msmgpio 21 0>;
+ qcom,te-gpio = <&msmgpio 22 0>;
+ qcom,rst-gpio = <&msmgpio 23 0>;
+ qcom,ad8-gpio = <&msmgpio 20 0>;
+ qcom,mdss-pan-res = <240 320>;
+ qcom,mdss-pan-bpp = <18>;
+ qcom,refresh_rate = <60>;
+ };
+};
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 9104f98..ce56b6b 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -177,9 +177,9 @@
}
if (atomic)
- clk_enable(tgt);
+ rc = clk_enable(tgt);
else
- clk_prepare_enable(tgt);
+ rc = clk_prepare_enable(tgt);
if (rc) {
pr_err("ACPU PLL enable failed\n");
@@ -195,9 +195,9 @@
} else {
if (atomic)
- clk_enable(tgt);
+ rc = clk_enable(tgt);
else
- clk_prepare_enable(tgt);
+ rc = clk_prepare_enable(tgt);
if (rc) {
pr_err("%s enable failed\n",
diff --git a/arch/arm/mach-msm/acpuclock-krait-debug.c b/arch/arm/mach-msm/acpuclock-krait-debug.c
index a29735e..f11b9fc 100644
--- a/arch/arm/mach-msm/acpuclock-krait-debug.c
+++ b/arch/arm/mach-msm/acpuclock-krait-debug.c
@@ -249,6 +249,56 @@
}
DEFINE_SIMPLE_ATTRIBUTE(boost_fops, boost_get, NULL, "%lld\n");
+static int acpu_table_show(struct seq_file *m, void *unused)
+{
+ const struct acpu_level *level;
+
+ seq_printf(m, "CPU_KHz PLL_L_Val L2_KHz VDD_Dig VDD_Mem ");
+ seq_printf(m, "BW_Mbps VDD_Core UA_Core AVS\n");
+
+ for (level = drv->acpu_freq_tbl; level->speed.khz != 0; level++) {
+
+ const struct l2_level *l2 =
+ &drv->l2_freq_tbl[level->l2_level];
+ u32 bw = drv->bus_scale->usecase[l2->bw_level].vectors[0].ib;
+
+ if (!level->use_for_scaling)
+ continue;
+
+ /* CPU speed information */
+ seq_printf(m, "%7lu %9u ",
+ level->speed.khz,
+ level->speed.pll_l_val);
+
+ /* L2 level information */
+ seq_printf(m, "%7lu %7d %7d %7u ",
+ l2->speed.khz,
+ l2->vdd_dig,
+ l2->vdd_mem,
+ bw / 1000000);
+
+ /* Core voltage information */
+ seq_printf(m, "%8d %7d %3d\n",
+ level->vdd_core,
+ level->ua_core,
+ level->avsdscr_setting);
+ }
+
+ return 0;
+}
+
+static int acpu_table_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpu_table_show, inode->i_private);
+}
+
+static const struct file_operations acpu_table_fops = {
+ .open = acpu_table_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static void __cpuinit add_scalable_dir(int sc_id)
{
char sc_name[8];
@@ -326,6 +376,8 @@
&speed_bin_fops);
debugfs_create_file("pvs_bin", S_IRUGO, base_dir, NULL, &pvs_bin_fops);
debugfs_create_file("boost_uv", S_IRUGO, base_dir, NULL, &boost_fops);
+ debugfs_create_file("acpu_table", S_IRUGO, base_dir, NULL,
+ &acpu_table_fops);
for_each_online_cpu(cpu)
add_scalable_dir(cpu);
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 1b76441..75aaaec 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -276,6 +276,57 @@
},
};
+static struct gpiomux_setting qpic_lcdc_a_d = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting qpic_lcdc_cs = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting qpic_lcdc_rs = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting qpic_lcdc_te = {
+ .func = GPIOMUX_FUNC_7,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm9625_qpic_lcdc_configs[] __initdata = {
+ {
+ .gpio = 20, /* a_d */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_a_d,
+ },
+ },
+ {
+ .gpio = 21, /* cs */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_cs,
+ },
+ },
+ {
+ .gpio = 22, /* te */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_te,
+ },
+ },
+ {
+ .gpio = 23, /* rs */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_rs,
+ },
+ },
+};
+
void __init msm9625_init_gpiomux(void)
{
int rc;
@@ -296,4 +347,7 @@
ARRAY_SIZE(mdm9625_cdc_reset_config));
msm_gpiomux_install(sdc2_card_det_config,
ARRAY_SIZE(sdc2_card_det_config));
+ msm_gpiomux_install(msm9625_qpic_lcdc_configs,
+ ARRAY_SIZE(msm9625_qpic_lcdc_configs));
+
}
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index c823c39..94a56c5 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3432,6 +3432,12 @@
static void __init msm8226_clock_post_init(void)
{
+ /*
+ * Hold an active set vote for CXO; this is because CXO is expected
+ * to remain on whenever CPUs aren't power collapsed.
+ */
+ clk_prepare_enable(&xo_a_clk.c);
+
/* Set rates for single-rate clocks. */
clk_set_rate(&usb_hs_system_clk_src.c,
usb_hs_system_clk_src.freq_tbl[0].freq_hz);
@@ -3517,12 +3523,6 @@
*/
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
- /*
- * Hold an active set vote for CXO; this is because CXO is expected
- * to remain on whenever CPUs aren't power collapsed.
- */
- clk_prepare_enable(&xo_a_clk.c);
-
enable_rpm_scaling();
reg_init();
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 8a06fe3..0cc7bbf 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -21,7 +21,7 @@
#define SCM_SVC_SSD 0x7
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
-#define SCM_SVC_CP 0xC
+#define SCM_SVC_MP 0xC
#define SCM_SVC_DCVS 0xD
#define SCM_SVC_TZSCHEDULER 0xFC
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 4336945..4adfe4d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -562,7 +562,7 @@
int pnode, src, curr, ctx;
uint64_t req_clk, req_bw, curr_clk, curr_bw;
struct msm_bus_client *client = (struct msm_bus_client *)cl;
- if (IS_ERR(client)) {
+ if (IS_ERR_OR_NULL(client)) {
MSM_BUS_ERR("msm_bus_scale_client update req error %d\n",
(uint32_t)client);
return -ENXIO;
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index ac993ea..50b2831 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -22,6 +22,8 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/opp.h>
+#include <linux/of.h>
+#include <linux/export.h>
/*
* Internal data structure organization with the OPP layer library is as
@@ -64,6 +66,7 @@
unsigned long u_volt;
struct device_opp *dev_opp;
+ struct rcu_head head;
};
/**
@@ -159,6 +162,7 @@
return v;
}
+EXPORT_SYMBOL(opp_get_voltage);
/**
* opp_get_freq() - Gets the frequency corresponding to an available opp
@@ -188,6 +192,7 @@
return f;
}
+EXPORT_SYMBOL(opp_get_freq);
/**
* opp_get_opp_count() - Get number of opps available in the opp list
@@ -220,6 +225,7 @@
return count;
}
+EXPORT_SYMBOL(opp_get_opp_count);
/**
* opp_find_freq_exact() - search for an exact frequency
@@ -229,7 +235,10 @@
*
* Searches for exact match in the opp list and returns pointer to the matching
* opp if found, else returns ERR_PTR in case of error and should be handled
- * using IS_ERR.
+ * using IS_ERR. Error return values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
*
* Note: available is a modifier for the search. if available=true, then the
* match is for exact matching frequency and is available in the stored OPP
@@ -248,7 +257,7 @@
bool available)
{
struct device_opp *dev_opp;
- struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+ struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
@@ -267,6 +276,7 @@
return opp;
}
+EXPORT_SYMBOL(opp_find_freq_exact);
/**
* opp_find_freq_ceil() - Search for an rounded ceil freq
@@ -277,7 +287,11 @@
* for a device.
*
* Returns matching *opp and refreshes *freq accordingly, else returns
- * ERR_PTR in case of error and should be handled using IS_ERR.
+ * ERR_PTR in case of error and should be handled using IS_ERR. Error return
+ * values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
*
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
* protected pointer. The reason for the same is that the opp pointer which is
@@ -288,7 +302,7 @@
struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
{
struct device_opp *dev_opp;
- struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+ struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
if (!dev || !freq) {
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -297,7 +311,7 @@
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp))
- return opp;
+ return ERR_CAST(dev_opp);
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
if (temp_opp->available && temp_opp->rate >= *freq) {
@@ -309,6 +323,7 @@
return opp;
}
+EXPORT_SYMBOL(opp_find_freq_ceil);
/**
* opp_find_freq_floor() - Search for a rounded floor freq
@@ -319,7 +334,11 @@
* for a device.
*
* Returns matching *opp and refreshes *freq accordingly, else returns
- * ERR_PTR in case of error and should be handled using IS_ERR.
+ * ERR_PTR in case of error and should be handled using IS_ERR. Error return
+ * values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
*
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
* protected pointer. The reason for the same is that the opp pointer which is
@@ -330,7 +349,7 @@
struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
{
struct device_opp *dev_opp;
- struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+ struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
if (!dev || !freq) {
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -339,7 +358,7 @@
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp))
- return opp;
+ return ERR_CAST(dev_opp);
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
if (temp_opp->available) {
@@ -355,6 +374,7 @@
return opp;
}
+EXPORT_SYMBOL(opp_find_freq_floor);
/**
* opp_add() - Add an OPP table from a table definitions
@@ -511,7 +531,7 @@
list_replace_rcu(&opp->node, &new_opp->node);
mutex_unlock(&dev_opp_list_lock);
- synchronize_rcu();
+ kfree_rcu(opp, head);
/* Notify the change of the OPP availability */
if (availability_req)
@@ -521,13 +541,10 @@
srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
new_opp);
- /* clean up old opp */
- new_opp = opp;
- goto out;
+ return 0;
unlock:
mutex_unlock(&dev_opp_list_lock);
-out:
kfree(new_opp);
return r;
}
@@ -551,6 +568,7 @@
{
return opp_set_availability(dev, freq, true);
}
+EXPORT_SYMBOL(opp_enable);
/**
* opp_disable() - Disable a specific OPP
@@ -572,6 +590,7 @@
{
return opp_set_availability(dev, freq, false);
}
+EXPORT_SYMBOL(opp_disable);
#ifdef CONFIG_CPU_FREQ
/**
@@ -674,3 +693,49 @@
return &dev_opp->head;
}
+
+#ifdef CONFIG_OF
+/**
+ * of_init_opp_table() - Initialize opp table from device tree
+ * @dev: device pointer used to lookup device OPPs.
+ *
+ * Register the initial OPP table with the OPP library for given device.
+ */
+int of_init_opp_table(struct device *dev)
+{
+ const struct property *prop;
+ const __be32 *val;
+ int nr;
+
+ prop = of_find_property(dev->of_node, "operating-points", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (!prop->value)
+ return -ENODATA;
+
+ /*
+ * Each OPP is a set of tuples consisting of frequency and
+ * voltage like <freq-kHz vol-uV>.
+ */
+ nr = prop->length / sizeof(u32);
+ if (nr % 2) {
+ dev_err(dev, "%s: Invalid OPP list\n", __func__);
+ return -EINVAL;
+ }
+
+ val = prop->value;
+ while (nr) {
+ unsigned long freq = be32_to_cpup(val++) * 1000;
+ unsigned long volt = be32_to_cpup(val++);
+
+ if (opp_add(dev, freq, volt)) {
+ dev_warn(dev, "%s: Failed to add OPP %ld\n",
+ __func__, freq);
+ continue;
+ }
+ nr -= 2;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 0f4d613..d78327f 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -138,6 +138,15 @@
struct hlist_head htbl[RPC_HASH_SZ];
};
+struct fastrpc_mmap {
+ struct hlist_node hn;
+ struct ion_handle *handle;
+ void *virt;
+ uint32_t vaddrin;
+ uint32_t vaddrout;
+ int size;
+};
+
struct fastrpc_buf {
struct ion_handle *handle;
void *virt;
@@ -146,6 +155,11 @@
int used;
};
+struct file_data {
+ spinlock_t hlock;
+ struct hlist_head hlst;
+};
+
struct fastrpc_device {
uint32_t tgid;
struct hlist_node hn;
@@ -168,18 +182,31 @@
}
}
+static void free_map(struct fastrpc_mmap *map)
+{
+ struct fastrpc_apps *me = &gfa;
+ if (map->handle) {
+ if (map->virt) {
+ ion_unmap_kernel(me->iclient, map->handle);
+ map->virt = 0;
+ }
+ ion_free(me->iclient, map->handle);
+ }
+ map->handle = 0;
+}
+
static int alloc_mem(struct fastrpc_buf *buf)
{
struct ion_client *clnt = gfa.iclient;
struct sg_table *sg;
int err = 0;
-
+ buf->handle = 0;
+ buf->virt = 0;
buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
ION_HEAP(ION_AUDIO_HEAP_ID), 0);
VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
if (err)
goto bail;
- buf->virt = 0;
VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
if (err)
goto bail;
@@ -211,7 +238,6 @@
static void context_list_dtor(struct smq_context_list *me)
{
kfree(me->ls);
- me->ls = 0;
}
static void context_list_alloc_ctx(struct smq_context_list *me,
@@ -277,7 +303,6 @@
if (rlen < 0) {
rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
obuf->size += buf_page_size(rlen);
- obuf->handle = 0;
VERIFY(err, 0 == alloc_mem(obuf));
if (err)
goto bail;
@@ -314,7 +339,6 @@
if (obuf->handle != ibuf->handle)
free_mem(obuf);
obuf->size += buf_page_size(sizeof(*pages));
- obuf->handle = 0;
VERIFY(err, 0 == alloc_mem(obuf));
if (err)
goto bail;
@@ -430,10 +454,15 @@
outbufs = REMOTE_SCALARS_OUTBUFS(sc);
for (i = inbufs; i < inbufs + outbufs; ++i) {
if (rpra[i].buf.pv != pra[i].buf.pv) {
- VERIFY(err, 0 == copy_to_user(pra[i].buf.pv,
+ if (!kernel) {
+ VERIFY(err, 0 == copy_to_user(pra[i].buf.pv,
rpra[i].buf.pv, rpra[i].buf.len));
- if (err)
- goto bail;
+ if (err)
+ goto bail;
+ } else {
+ memmove(pra[i].buf.pv, rpra[i].buf.pv,
+ rpra[i].buf.len);
+ }
}
}
size = sizeof(*rpra) * REMOTE_SCALARS_OUTHANDLES(sc);
@@ -471,15 +500,17 @@
dmac_inv_range(rpra, (char *)rpra + used);
}
-static int fastrpc_invoke_send(struct fastrpc_apps *me, uint32_t handle,
+static int fastrpc_invoke_send(struct fastrpc_apps *me,
+ uint32_t kernel, uint32_t handle,
uint32_t sc, struct smq_invoke_ctx *ctx,
struct fastrpc_buf *buf)
{
struct smq_msg msg;
int err = 0, len;
-
msg.pid = current->tgid;
msg.tid = current->pid;
+ if (kernel)
+ msg.pid = 0;
msg.invoke.header.ctx = ctx;
msg.invoke.header.handle = handle;
msg.invoke.header.sc = sc;
@@ -595,12 +626,15 @@
VERIFY(err, 0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
if (err)
goto bail;
+
+ INIT_HLIST_NODE(&fd->hn);
+
fd->buf.size = PAGE_SIZE;
VERIFY(err, 0 == alloc_mem(&fd->buf));
if (err)
goto bail;
fd->tgid = current->tgid;
- INIT_HLIST_NODE(&fd->hn);
+
*dev = fd;
bail:
if (err)
@@ -681,8 +715,8 @@
}
context_list_alloc_ctx(&me->clst, &ctx);
- VERIFY(err, 0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx,
- &obuf));
+ VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
+ ctx, &obuf));
if (err)
goto bail;
inv_args(sc, rpra, obuf.used);
@@ -730,7 +764,7 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
ioctl.pra = ra;
- VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
return err;
}
@@ -748,7 +782,155 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
ioctl.pra = ra;
- VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
+ return err;
+}
+
+static int fastrpc_mmap_on_dsp(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_mmap *mmap,
+ struct smq_phy_page *pages,
+ int num)
+{
+ struct fastrpc_ioctl_invoke ioctl;
+ remote_arg_t ra[3];
+ int err = 0;
+ struct {
+ int pid;
+ uint32_t flags;
+ uint32_t vaddrin;
+ int num;
+ } inargs;
+
+ struct {
+ uint32_t vaddrout;
+ } routargs;
+ inargs.pid = current->tgid;
+ inargs.vaddrin = mmap->vaddrin;
+ inargs.flags = mmap->flags;
+ inargs.num = num;
+ ra[0].buf.pv = &inargs;
+ ra[0].buf.len = sizeof(inargs);
+
+ ra[1].buf.pv = pages;
+ ra[1].buf.len = num * sizeof(*pages);
+
+ ra[2].buf.pv = &routargs;
+ ra[2].buf.len = sizeof(routargs);
+
+ ioctl.handle = 1;
+ ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+ ioctl.pra = ra;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
+ mmap->vaddrout = routargs.vaddrout;
+ if (err)
+ goto bail;
+bail:
+ return err;
+}
+
+static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_munmap *munmap)
+{
+ struct fastrpc_ioctl_invoke ioctl;
+ remote_arg_t ra[1];
+ int err = 0;
+ struct {
+ int pid;
+ uint32_t vaddrout;
+ int size;
+ } inargs;
+
+ inargs.pid = current->tgid;
+ inargs.size = munmap->size;
+ inargs.vaddrout = munmap->vaddrout;
+ ra[0].buf.pv = &inargs;
+ ra[0].buf.len = sizeof(inargs);
+
+ ioctl.handle = 1;
+ ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+ ioctl.pra = ra;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
+ return err;
+}
+
+static int fastrpc_internal_munmap(struct fastrpc_apps *me,
+ struct file_data *fdata,
+ struct fastrpc_ioctl_munmap *munmap)
+{
+ int err = 0;
+ struct fastrpc_mmap *map = 0, *mapfree = 0;
+ struct hlist_node *pos, *n;
+ VERIFY(err, 0 == (err = fastrpc_munmap_on_dsp(me, munmap)));
+ if (err)
+ goto bail;
+ spin_lock(&fdata->hlock);
+ hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
+ if (map->vaddrout == munmap->vaddrout &&
+ map->size == munmap->size) {
+ hlist_del(&map->hn);
+ mapfree = map;
+ map = 0;
+ break;
+ }
+ }
+ spin_unlock(&fdata->hlock);
+bail:
+ if (mapfree) {
+ free_map(mapfree);
+ kfree(mapfree);
+ }
+ return err;
+}
+
+
+static int fastrpc_internal_mmap(struct fastrpc_apps *me,
+ struct file_data *fdata,
+ struct fastrpc_ioctl_mmap *mmap)
+{
+ struct ion_client *clnt = gfa.iclient;
+ struct fastrpc_mmap *map = 0;
+ struct smq_phy_page *pages = 0;
+ void *buf;
+ int len;
+ int num;
+ int err = 0;
+
+ VERIFY(err, 0 != (map = kzalloc(sizeof(*map), GFP_KERNEL)));
+ if (err)
+ goto bail;
+ map->handle = ion_import_dma_buf(clnt, mmap->fd);
+ VERIFY(err, 0 == IS_ERR_OR_NULL(map->handle));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (map->virt = ion_map_kernel(clnt, map->handle)));
+ if (err)
+ goto bail;
+ buf = (void *)mmap->vaddrin;
+ len = mmap->size;
+ num = buf_num_pages(buf, len);
+ VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
+ if (err)
+ goto bail;
+
+ VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
+ if (err)
+ goto bail;
+ map->vaddrin = mmap->vaddrin;
+ map->vaddrout = mmap->vaddrout;
+ map->size = mmap->size;
+ INIT_HLIST_NODE(&map->hn);
+ spin_lock(&fdata->hlock);
+ hlist_add_head(&map->hn, &fdata->hlst);
+ spin_unlock(&fdata->hlock);
+ bail:
+ if (err && map) {
+ free_map(map);
+ kfree(map);
+ }
+ kfree(pages);
return err;
}
@@ -781,22 +963,48 @@
static int fastrpc_device_release(struct inode *inode, struct file *file)
{
+ struct file_data *fdata = (struct file_data *)file->private_data;
(void)fastrpc_release_current_dsp_process();
cleanup_current_dev();
+ if (fdata) {
+ struct fastrpc_mmap *map;
+ struct hlist_node *n, *pos;
+ file->private_data = 0;
+ hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
+ hlist_del(&map->hn);
+ free_map(map);
+ kfree(map);
+ }
+ kfree(fdata);
+ }
return 0;
}
static int fastrpc_device_open(struct inode *inode, struct file *filp)
{
int err = 0;
-
+ filp->private_data = 0;
if (0 != try_module_get(THIS_MODULE)) {
+ struct file_data *fdata = 0;
/* This call will cause a dev to be created
* which will addref this module
*/
+ VERIFY(err, 0 != (fdata = kzalloc(sizeof(*fdata), GFP_KERNEL)));
+ if (err)
+ goto bail;
+
+ spin_lock_init(&fdata->hlock);
+ INIT_HLIST_HEAD(&fdata->hlst);
+
VERIFY(err, 0 == fastrpc_create_current_dsp_process());
if (err)
+ goto bail;
+ filp->private_data = fdata;
+bail:
+ if (err) {
cleanup_current_dev();
+ kfree(fdata);
+ }
module_put(THIS_MODULE);
}
return err;
@@ -808,8 +1016,11 @@
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_ioctl_invoke invoke;
+ struct fastrpc_ioctl_mmap mmap;
+ struct fastrpc_ioctl_munmap munmap;
remote_arg_t *pra = 0;
void *param = (char *)ioctl_param;
+ struct file_data *fdata = (struct file_data *)file->private_data;
int bufs, err = 0;
switch (ioctl_num) {
@@ -834,6 +1045,29 @@
if (err)
goto bail;
break;
+ case FASTRPC_IOCTL_MMAP:
+ VERIFY(err, 0 == copy_from_user(&mmap, param,
+ sizeof(mmap)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_mmap(me, fdata,
+ &mmap)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == copy_to_user(param, &mmap, sizeof(mmap)));
+ if (err)
+ goto bail;
+ break;
+ case FASTRPC_IOCTL_MUNMAP:
+ VERIFY(err, 0 == copy_from_user(&munmap, param,
+ sizeof(munmap)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_munmap(me, fdata,
+ &munmap)));
+ if (err)
+ goto bail;
+ break;
default:
err = -ENOTTY;
break;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 8932d3c..f2804ad 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -16,7 +16,9 @@
#include <linux/types.h>
-#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
+#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
+#define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap)
+#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap)
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
@@ -92,6 +94,20 @@
remote_arg_t *pra; /* remote arguments list */
};
+struct fastrpc_ioctl_munmap {
+ uint32_t vaddrout; /* address to unmap */
+ int size; /* size */
+};
+
+
+struct fastrpc_ioctl_mmap {
+ int fd; /* ion fd */
+ uint32_t flags; /* flags for dsp to map with */
+ uint32_t vaddrin; /* optional virtual address */
+ int size; /* size */
+ uint32_t vaddrout; /* dsps virtual address */
+};
+
struct smq_null_invoke {
struct smq_invoke_ctx *ctx; /* invoke caller context */
uint32_t handle; /* handle to invoke */
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 70c31d4..2ab79d2 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -27,21 +27,17 @@
#include <linux/hrtimer.h>
#include "governor.h"
-struct class *devfreq_class;
+static struct class *devfreq_class;
/*
- * devfreq_work periodically monitors every registered device.
- * The minimum polling interval is one jiffy. The polling interval is
- * determined by the minimum polling period among all polling devfreq
- * devices. The resolution of polling interval is one jiffy.
+ * devfreq core provides delayed work based load monitoring helper
+ * functions. Governors can use these or can implement their own
+ * monitoring mechanism.
*/
-static bool polling;
static struct workqueue_struct *devfreq_wq;
-static struct delayed_work devfreq_work;
-/* wait removing if this is to be removed */
-static struct devfreq *wait_remove_device;
-
+/* The list of all device-devfreq governors */
+static LIST_HEAD(devfreq_governor_list);
/* The list of all device-devfreq */
static LIST_HEAD(devfreq_list);
static DEFINE_MUTEX(devfreq_list_lock);
@@ -73,6 +69,79 @@
}
/**
+ * devfreq_get_freq_level() - Lookup freq_table for the frequency
+ * @devfreq: the devfreq instance
+ * @freq: the target frequency
+ */
+static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
+{
+ int lev;
+
+ for (lev = 0; lev < devfreq->profile->max_state; lev++)
+ if (freq == devfreq->profile->freq_table[lev])
+ return lev;
+
+ return -EINVAL;
+}
+
+/**
+ * devfreq_update_status() - Update statistics of devfreq behavior
+ * @devfreq: the devfreq instance
+ * @freq: the update target frequency
+ */
+static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
+{
+ int lev, prev_lev;
+ unsigned long cur_time;
+
+ lev = devfreq_get_freq_level(devfreq, freq);
+ if (lev < 0)
+ return lev;
+
+ cur_time = jiffies;
+ devfreq->time_in_state[lev] +=
+ cur_time - devfreq->last_stat_updated;
+ if (freq != devfreq->previous_freq) {
+ prev_lev = devfreq_get_freq_level(devfreq,
+ devfreq->previous_freq);
+ devfreq->trans_table[(prev_lev *
+ devfreq->profile->max_state) + lev]++;
+ devfreq->total_trans++;
+ }
+ devfreq->last_stat_updated = cur_time;
+
+ return 0;
+}
+
+/**
+ * find_devfreq_governor() - find devfreq governor from name
+ * @name: name of the governor
+ *
+ * Search the list of devfreq governors and return the matched
+ * governor's pointer. devfreq_list_lock should be held by the caller.
+ */
+static struct devfreq_governor *find_devfreq_governor(const char *name)
+{
+ struct devfreq_governor *tmp_governor;
+
+ if (unlikely(IS_ERR_OR_NULL(name))) {
+ pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+ WARN(!mutex_is_locked(&devfreq_list_lock),
+ "devfreq_list_lock must be locked.");
+
+ list_for_each_entry(tmp_governor, &devfreq_governor_list, node) {
+ if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN))
+ return tmp_governor;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+/* Load monitoring helper functions for governors use */
+
+/**
* update_devfreq() - Reevaluate the device and configure frequency.
* @devfreq: the devfreq instance.
*
@@ -116,16 +185,168 @@
if (err)
return err;
+ if (devfreq->profile->freq_table)
+ if (devfreq_update_status(devfreq, freq))
+ dev_err(&devfreq->dev,
+ "Couldn't update frequency transition information.\n");
+
devfreq->previous_freq = freq;
return err;
}
+EXPORT_SYMBOL(update_devfreq);
+
+/**
+ * devfreq_monitor() - Periodically poll devfreq objects.
+ * @work: the work struct used to run devfreq_monitor periodically.
+ *
+ */
+static void devfreq_monitor(struct work_struct *work)
+{
+ int err;
+ struct devfreq *devfreq = container_of(work,
+ struct devfreq, work.work);
+
+ mutex_lock(&devfreq->lock);
+ err = update_devfreq(devfreq);
+ if (err)
+ dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
+
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ mutex_unlock(&devfreq->lock);
+}
+
+/**
+ * devfreq_monitor_start() - Start load monitoring of devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function for starting devfreq device load monitoing. By
+ * default delayed work based monitoring is supported. Function
+ * to be called from governor in response to DEVFREQ_GOV_START
+ * event when device is added to devfreq framework.
+ */
+void devfreq_monitor_start(struct devfreq *devfreq)
+{
+ INIT_DELAYED_WORK_DEFERRABLE(&devfreq->work, devfreq_monitor);
+ if (devfreq->profile->polling_ms)
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+}
+
+/**
+ * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function to stop devfreq device load monitoing. Function
+ * to be called from governor in response to DEVFREQ_GOV_STOP
+ * event when device is removed from devfreq framework.
+ */
+void devfreq_monitor_stop(struct devfreq *devfreq)
+{
+ cancel_delayed_work_sync(&devfreq->work);
+}
+
+/**
+ * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function to suspend devfreq device load monitoing. Function
+ * to be called from governor in response to DEVFREQ_GOV_SUSPEND
+ * event or when polling interval is set to zero.
+ *
+ * Note: Though this function is same as devfreq_monitor_stop(),
+ * intentionally kept separate to provide hooks for collecting
+ * transition statistics.
+ */
+void devfreq_monitor_suspend(struct devfreq *devfreq)
+{
+ mutex_lock(&devfreq->lock);
+ if (devfreq->stop_polling) {
+ mutex_unlock(&devfreq->lock);
+ return;
+ }
+
+ devfreq->stop_polling = true;
+ mutex_unlock(&devfreq->lock);
+ cancel_delayed_work_sync(&devfreq->work);
+}
+
+/**
+ * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function to resume devfreq device load monitoing. Function
+ * to be called from governor in response to DEVFREQ_GOV_RESUME
+ * event or when polling interval is set to non-zero.
+ */
+void devfreq_monitor_resume(struct devfreq *devfreq)
+{
+ mutex_lock(&devfreq->lock);
+ if (!devfreq->stop_polling)
+ goto out;
+
+ if (!delayed_work_pending(&devfreq->work) &&
+ devfreq->profile->polling_ms)
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ devfreq->stop_polling = false;
+
+out:
+ mutex_unlock(&devfreq->lock);
+}
+
+/**
+ * devfreq_interval_update() - Update device devfreq monitoring interval
+ * @devfreq: the devfreq instance.
+ * @delay: new polling interval to be set.
+ *
+ * Helper function to set new load monitoring polling interval. Function
+ * to be called from governor in response to DEVFREQ_GOV_INTERVAL event.
+ */
+void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
+{
+ unsigned int cur_delay = devfreq->profile->polling_ms;
+ unsigned int new_delay = *delay;
+
+ mutex_lock(&devfreq->lock);
+ devfreq->profile->polling_ms = new_delay;
+
+ if (devfreq->stop_polling)
+ goto out;
+
+ /* if new delay is zero, stop polling */
+ if (!new_delay) {
+ mutex_unlock(&devfreq->lock);
+ cancel_delayed_work_sync(&devfreq->work);
+ return;
+ }
+
+ /* if current delay is zero, start polling with new delay */
+ if (!cur_delay) {
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ goto out;
+ }
+
+ /* if current delay is greater than new delay, restart polling */
+ if (cur_delay > new_delay) {
+ mutex_unlock(&devfreq->lock);
+ cancel_delayed_work_sync(&devfreq->work);
+ mutex_lock(&devfreq->lock);
+ if (!devfreq->stop_polling)
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ }
+out:
+ mutex_unlock(&devfreq->lock);
+}
/**
* devfreq_notifier_call() - Notify that the device frequency requirements
* has been changed out of devfreq framework.
- * @nb the notifier_block (supposed to be devfreq->nb)
- * @type not used
- * @devp not used
+ * @nb: the notifier_block (supposed to be devfreq->nb)
+ * @type: not used
+ * @devp: not used
*
* Called by a notifier that uses devfreq->nb.
*/
@@ -143,59 +364,32 @@
}
/**
- * _remove_devfreq() - Remove devfreq from the device.
+ * _remove_devfreq() - Remove devfreq from the list and release its resources.
* @devfreq: the devfreq struct
* @skip: skip calling device_unregister().
- *
- * Note that the caller should lock devfreq->lock before calling
- * this. _remove_devfreq() will unlock it and free devfreq
- * internally. devfreq_list_lock should be locked by the caller
- * as well (not relased at return)
- *
- * Lock usage:
- * devfreq->lock: locked before call.
- * unlocked at return (and freed)
- * devfreq_list_lock: locked before call.
- * kept locked at return.
- * if devfreq is centrally polled.
- *
- * Freed memory:
- * devfreq
*/
static void _remove_devfreq(struct devfreq *devfreq, bool skip)
{
- if (!mutex_is_locked(&devfreq->lock)) {
- WARN(true, "devfreq->lock must be locked by the caller.\n");
+ mutex_lock(&devfreq_list_lock);
+ if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
+ mutex_unlock(&devfreq_list_lock);
+ dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
return;
}
- if (!devfreq->governor->no_central_polling &&
- !mutex_is_locked(&devfreq_list_lock)) {
- WARN(true, "devfreq_list_lock must be locked by the caller.\n");
- return;
- }
+ list_del(&devfreq->node);
+ mutex_unlock(&devfreq_list_lock);
- if (devfreq->being_removed)
- return;
-
- devfreq->being_removed = true;
+ devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL);
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
- if (devfreq->governor->exit)
- devfreq->governor->exit(devfreq);
-
if (!skip && get_device(&devfreq->dev)) {
device_unregister(&devfreq->dev);
put_device(&devfreq->dev);
}
- if (!devfreq->governor->no_central_polling)
- list_del(&devfreq->node);
-
- mutex_unlock(&devfreq->lock);
mutex_destroy(&devfreq->lock);
-
kfree(devfreq);
}
@@ -210,130 +404,8 @@
static void devfreq_dev_release(struct device *dev)
{
struct devfreq *devfreq = to_devfreq(dev);
- bool central_polling = !devfreq->governor->no_central_polling;
- /*
- * If devfreq_dev_release() was called by device_unregister() of
- * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and
- * being_removed is already set. This also partially checks the case
- * where devfreq_dev_release() is called from a thread other than
- * the one called _remove_devfreq(); however, this case is
- * dealt completely with another following being_removed check.
- *
- * Because being_removed is never being
- * unset, we do not need to worry about race conditions on
- * being_removed.
- */
- if (devfreq->being_removed)
- return;
-
- if (central_polling)
- mutex_lock(&devfreq_list_lock);
-
- mutex_lock(&devfreq->lock);
-
- /*
- * Check being_removed flag again for the case where
- * devfreq_dev_release() was called in a thread other than the one
- * possibly called _remove_devfreq().
- */
- if (devfreq->being_removed) {
- mutex_unlock(&devfreq->lock);
- goto out;
- }
-
- /* devfreq->lock is unlocked and removed in _removed_devfreq() */
_remove_devfreq(devfreq, true);
-
-out:
- if (central_polling)
- mutex_unlock(&devfreq_list_lock);
-}
-
-/**
- * devfreq_monitor() - Periodically poll devfreq objects.
- * @work: the work struct used to run devfreq_monitor periodically.
- *
- */
-static void devfreq_monitor(struct work_struct *work)
-{
- static unsigned long last_polled_at;
- struct devfreq *devfreq, *tmp;
- int error;
- unsigned long jiffies_passed;
- unsigned long next_jiffies = ULONG_MAX, now = jiffies;
- struct device *dev;
-
- /* Initially last_polled_at = 0, polling every device at bootup */
- jiffies_passed = now - last_polled_at;
- last_polled_at = now;
- if (jiffies_passed == 0)
- jiffies_passed = 1;
-
- mutex_lock(&devfreq_list_lock);
- list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) {
- mutex_lock(&devfreq->lock);
- dev = devfreq->dev.parent;
-
- /* Do not remove tmp for a while */
- wait_remove_device = tmp;
-
- if (devfreq->governor->no_central_polling ||
- devfreq->next_polling == 0) {
- mutex_unlock(&devfreq->lock);
- continue;
- }
- mutex_unlock(&devfreq_list_lock);
-
- /*
- * Reduce more next_polling if devfreq_wq took an extra
- * delay. (i.e., CPU has been idled.)
- */
- if (devfreq->next_polling <= jiffies_passed) {
- error = update_devfreq(devfreq);
-
- /* Remove a devfreq with an error. */
- if (error && error != -EAGAIN) {
-
- dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n",
- error, devfreq->governor->name);
-
- /*
- * Unlock devfreq before locking the list
- * in order to avoid deadlock with
- * find_device_devfreq or others
- */
- mutex_unlock(&devfreq->lock);
- mutex_lock(&devfreq_list_lock);
- /* Check if devfreq is already removed */
- if (IS_ERR(find_device_devfreq(dev)))
- continue;
- mutex_lock(&devfreq->lock);
- /* This unlocks devfreq->lock and free it */
- _remove_devfreq(devfreq, false);
- continue;
- }
- devfreq->next_polling = devfreq->polling_jiffies;
- } else {
- devfreq->next_polling -= jiffies_passed;
- }
-
- if (devfreq->next_polling)
- next_jiffies = (next_jiffies > devfreq->next_polling) ?
- devfreq->next_polling : next_jiffies;
-
- mutex_unlock(&devfreq->lock);
- mutex_lock(&devfreq_list_lock);
- }
- wait_remove_device = NULL;
- mutex_unlock(&devfreq_list_lock);
-
- if (next_jiffies > 0 && next_jiffies < ULONG_MAX) {
- polling = true;
- queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies);
- } else {
- polling = false;
- }
}
/**
@@ -357,16 +429,13 @@
return ERR_PTR(-EINVAL);
}
-
- if (!governor->no_central_polling) {
- mutex_lock(&devfreq_list_lock);
- devfreq = find_device_devfreq(dev);
- mutex_unlock(&devfreq_list_lock);
- if (!IS_ERR(devfreq)) {
- dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
- err = -EINVAL;
- goto err_out;
- }
+ mutex_lock(&devfreq_list_lock);
+ devfreq = find_device_devfreq(dev);
+ mutex_unlock(&devfreq_list_lock);
+ if (!IS_ERR(devfreq)) {
+ dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
+ err = -EINVAL;
+ goto err_out;
}
devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
@@ -386,79 +455,156 @@
devfreq->governor = governor;
devfreq->previous_freq = profile->initial_freq;
devfreq->data = data;
- devfreq->next_polling = devfreq->polling_jiffies
- = msecs_to_jiffies(devfreq->profile->polling_ms);
devfreq->nb.notifier_call = devfreq_notifier_call;
+ devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) *
+ devfreq->profile->max_state *
+ devfreq->profile->max_state,
+ GFP_KERNEL);
+ devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) *
+ devfreq->profile->max_state,
+ GFP_KERNEL);
+ devfreq->last_stat_updated = jiffies;
+
dev_set_name(&devfreq->dev, dev_name(dev));
err = device_register(&devfreq->dev);
if (err) {
put_device(&devfreq->dev);
+ mutex_unlock(&devfreq->lock);
goto err_dev;
}
- if (governor->init)
- err = governor->init(devfreq);
- if (err)
- goto err_init;
-
mutex_unlock(&devfreq->lock);
- if (governor->no_central_polling)
- goto out;
-
mutex_lock(&devfreq_list_lock);
-
list_add(&devfreq->node, &devfreq_list);
-
- if (devfreq_wq && devfreq->next_polling && !polling) {
- polling = true;
- queue_delayed_work(devfreq_wq, &devfreq_work,
- devfreq->next_polling);
- }
mutex_unlock(&devfreq_list_lock);
-out:
+
+ err = devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_START, NULL);
+ if (err) {
+ dev_err(dev, "%s: Unable to start governor for the device\n",
+ __func__);
+ goto err_init;
+ }
+
return devfreq;
err_init:
+ list_del(&devfreq->node);
device_unregister(&devfreq->dev);
err_dev:
- mutex_unlock(&devfreq->lock);
kfree(devfreq);
err_out:
return ERR_PTR(err);
}
+EXPORT_SYMBOL(devfreq_add_device);
/**
* devfreq_remove_device() - Remove devfreq feature from a device.
- * @devfreq the devfreq instance to be removed
+ * @devfreq: the devfreq instance to be removed
*/
int devfreq_remove_device(struct devfreq *devfreq)
{
- bool central_polling;
-
if (!devfreq)
return -EINVAL;
- central_polling = !devfreq->governor->no_central_polling;
-
- if (central_polling) {
- mutex_lock(&devfreq_list_lock);
- while (wait_remove_device == devfreq) {
- mutex_unlock(&devfreq_list_lock);
- schedule();
- mutex_lock(&devfreq_list_lock);
- }
- }
-
- mutex_lock(&devfreq->lock);
- _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */
-
- if (central_polling)
- mutex_unlock(&devfreq_list_lock);
+ _remove_devfreq(devfreq, false);
return 0;
}
+EXPORT_SYMBOL(devfreq_remove_device);
+
+/**
+ * devfreq_suspend_device() - Suspend devfreq of a device.
+ * @devfreq: the devfreq instance to be suspended
+ */
+int devfreq_suspend_device(struct devfreq *devfreq)
+{
+ if (!devfreq)
+ return -EINVAL;
+
+ return devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_SUSPEND, NULL);
+}
+EXPORT_SYMBOL(devfreq_suspend_device);
+
+/**
+ * devfreq_resume_device() - Resume devfreq of a device.
+ * @devfreq: the devfreq instance to be resumed
+ */
+int devfreq_resume_device(struct devfreq *devfreq)
+{
+ if (!devfreq)
+ return -EINVAL;
+
+ return devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_RESUME, NULL);
+}
+EXPORT_SYMBOL(devfreq_resume_device);
+
+/**
+ * devfreq_add_governor() - Add devfreq governor
+ * @governor: the devfreq governor to be added
+ */
+int devfreq_add_governor(struct devfreq_governor *governor)
+{
+ struct devfreq_governor *g;
+ int err = 0;
+
+ if (!governor) {
+ pr_err("%s: Invalid parameters.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&devfreq_list_lock);
+ g = find_devfreq_governor(governor->name);
+ if (!IS_ERR(g)) {
+ pr_err("%s: governor %s already registered\n", __func__,
+ g->name);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ list_add(&governor->node, &devfreq_governor_list);
+
+err_out:
+ mutex_unlock(&devfreq_list_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(devfreq_add_governor);
+
+/**
+ * devfreq_remove_device() - Remove devfreq feature from a device.
+ * @governor: the devfreq governor to be removed
+ */
+int devfreq_remove_governor(struct devfreq_governor *governor)
+{
+ struct devfreq_governor *g;
+ int err = 0;
+
+ if (!governor) {
+ pr_err("%s: Invalid parameters.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&devfreq_list_lock);
+ g = find_devfreq_governor(governor->name);
+ if (IS_ERR(g)) {
+ pr_err("%s: governor %s not registered\n", __func__,
+ g->name);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ list_del(&governor->node);
+err_out:
+ mutex_unlock(&devfreq_list_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(devfreq_remove_governor);
static ssize_t show_governor(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -469,6 +615,19 @@
static ssize_t show_freq(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ unsigned long freq;
+ struct devfreq *devfreq = to_devfreq(dev);
+
+ if (devfreq->profile->get_cur_freq &&
+ !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
+ return sprintf(buf, "%lu\n", freq);
+
+ return sprintf(buf, "%lu\n", devfreq->previous_freq);
+}
+
+static ssize_t show_target_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
}
@@ -488,37 +647,14 @@
ret = sscanf(buf, "%u", &value);
if (ret != 1)
- goto out;
+ return -EINVAL;
- mutex_lock(&df->lock);
- df->profile->polling_ms = value;
- df->next_polling = df->polling_jiffies
- = msecs_to_jiffies(value);
- mutex_unlock(&df->lock);
-
+ df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value);
ret = count;
- if (df->governor->no_central_polling)
- goto out;
-
- mutex_lock(&devfreq_list_lock);
- if (df->next_polling > 0 && !polling) {
- polling = true;
- queue_delayed_work(devfreq_wq, &devfreq_work,
- df->next_polling);
- }
- mutex_unlock(&devfreq_list_lock);
-out:
return ret;
}
-static ssize_t show_central_polling(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n",
- !to_devfreq(dev)->governor->no_central_polling);
-}
-
static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -529,7 +665,7 @@
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
- goto out;
+ return -EINVAL;
mutex_lock(&df->lock);
max = df->max_freq;
@@ -543,7 +679,6 @@
ret = count;
unlock:
mutex_unlock(&df->lock);
-out:
return ret;
}
@@ -563,7 +698,7 @@
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
- goto out;
+ return -EINVAL;
mutex_lock(&df->lock);
min = df->min_freq;
@@ -577,7 +712,6 @@
ret = count;
unlock:
mutex_unlock(&df->lock);
-out:
return ret;
}
@@ -587,34 +721,91 @@
return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
}
+static ssize_t show_available_freqs(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq *df = to_devfreq(d);
+ struct device *dev = df->dev.parent;
+ struct opp *opp;
+ ssize_t count = 0;
+ unsigned long freq = 0;
+
+ rcu_read_lock();
+ do {
+ opp = opp_find_freq_ceil(dev, &freq);
+ if (IS_ERR(opp))
+ break;
+
+ count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+ "%lu ", freq);
+ freq++;
+ } while (1);
+ rcu_read_unlock();
+
+ /* Truncate the trailing space */
+ if (count)
+ count--;
+
+ count += sprintf(&buf[count], "\n");
+
+ return count;
+}
+
+static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq *devfreq = to_devfreq(dev);
+ ssize_t len;
+ int i, j, err;
+ unsigned int max_state = devfreq->profile->max_state;
+
+ err = devfreq_update_status(devfreq, devfreq->previous_freq);
+ if (err)
+ return 0;
+
+ len = sprintf(buf, " From : To\n");
+ len += sprintf(buf + len, " :");
+ for (i = 0; i < max_state; i++)
+ len += sprintf(buf + len, "%8u",
+ devfreq->profile->freq_table[i]);
+
+ len += sprintf(buf + len, " time(ms)\n");
+
+ for (i = 0; i < max_state; i++) {
+ if (devfreq->profile->freq_table[i]
+ == devfreq->previous_freq) {
+ len += sprintf(buf + len, "*");
+ } else {
+ len += sprintf(buf + len, " ");
+ }
+ len += sprintf(buf + len, "%8u:",
+ devfreq->profile->freq_table[i]);
+ for (j = 0; j < max_state; j++)
+ len += sprintf(buf + len, "%8u",
+ devfreq->trans_table[(i * max_state) + j]);
+ len += sprintf(buf + len, "%10u\n",
+ jiffies_to_msecs(devfreq->time_in_state[i]));
+ }
+
+ len += sprintf(buf + len, "Total transition : %u\n",
+ devfreq->total_trans);
+ return len;
+}
+
static struct device_attribute devfreq_attrs[] = {
__ATTR(governor, S_IRUGO, show_governor, NULL),
__ATTR(cur_freq, S_IRUGO, show_freq, NULL),
- __ATTR(central_polling, S_IRUGO, show_central_polling, NULL),
+ __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL),
+ __ATTR(target_freq, S_IRUGO, show_target_freq, NULL),
__ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
store_polling_interval),
__ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
__ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
+ __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
{ },
};
-/**
- * devfreq_start_polling() - Initialize data structure for devfreq framework and
- * start polling registered devfreq devices.
- */
-static int __init devfreq_start_polling(void)
-{
- mutex_lock(&devfreq_list_lock);
- polling = false;
- devfreq_wq = create_freezable_workqueue("devfreq_wq");
- INIT_DELAYED_WORK_DEFERRABLE(&devfreq_work, devfreq_monitor);
- mutex_unlock(&devfreq_list_lock);
-
- devfreq_monitor(&devfreq_work.work);
- return 0;
-}
-late_initcall(devfreq_start_polling);
-
static int __init devfreq_init(void)
{
devfreq_class = class_create(THIS_MODULE, "devfreq");
@@ -622,7 +813,15 @@
pr_err("%s: couldn't create class\n", __FILE__);
return PTR_ERR(devfreq_class);
}
+
+ devfreq_wq = create_freezable_workqueue("devfreq_wq");
+ if (IS_ERR(devfreq_wq)) {
+ class_destroy(devfreq_class);
+ pr_err("%s: couldn't create workqueue\n", __FILE__);
+ return PTR_ERR(devfreq_wq);
+ }
devfreq_class->dev_attrs = devfreq_attrs;
+
return 0;
}
subsys_initcall(devfreq_init);
@@ -630,6 +829,7 @@
static void __exit devfreq_exit(void)
{
class_destroy(devfreq_class);
+ destroy_workqueue(devfreq_wq);
}
module_exit(devfreq_exit);
@@ -641,9 +841,9 @@
/**
* devfreq_recommended_opp() - Helper function to get proper OPP for the
* freq value given to target callback.
- * @dev The devfreq user device. (parent of devfreq)
- * @freq The frequency given to target function
- * @flags Flags handed from devfreq framework.
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @freq: The frequency given to target function
+ * @flags: Flags handed from devfreq framework.
*
*/
struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
@@ -656,14 +856,14 @@
opp = opp_find_freq_floor(dev, freq);
/* If not available, use the closest opp */
- if (opp == ERR_PTR(-ENODEV))
+ if (opp == ERR_PTR(-ERANGE))
opp = opp_find_freq_ceil(dev, freq);
} else {
/* The freq is an lower bound. opp should be higher */
opp = opp_find_freq_ceil(dev, freq);
/* If not available, use the closest opp */
- if (opp == ERR_PTR(-ENODEV))
+ if (opp == ERR_PTR(-ERANGE))
opp = opp_find_freq_floor(dev, freq);
}
@@ -674,8 +874,8 @@
* devfreq_register_opp_notifier() - Helper function to get devfreq notified
* for any changes in the OPP availability
* changes
- * @dev The devfreq user device. (parent of devfreq)
- * @devfreq The devfreq object.
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
*/
int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
{
@@ -690,8 +890,8 @@
* devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
* notified for any changes in the OPP
* availability changes anymore.
- * @dev The devfreq user device. (parent of devfreq)
- * @devfreq The devfreq object.
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
*
* At exit() callback of devfreq_dev_profile, this must be included if
* devfreq_recommended_opp is used.
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
index ea7f13c..fad7d63 100644
--- a/drivers/devfreq/governor.h
+++ b/drivers/devfreq/governor.h
@@ -18,7 +18,24 @@
#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
+/* Devfreq events */
+#define DEVFREQ_GOV_START 0x1
+#define DEVFREQ_GOV_STOP 0x2
+#define DEVFREQ_GOV_INTERVAL 0x3
+#define DEVFREQ_GOV_SUSPEND 0x4
+#define DEVFREQ_GOV_RESUME 0x5
+
/* Caution: devfreq->lock must be locked before calling update_devfreq */
extern int update_devfreq(struct devfreq *devfreq);
+extern void devfreq_monitor_start(struct devfreq *devfreq);
+extern void devfreq_monitor_stop(struct devfreq *devfreq);
+extern void devfreq_monitor_suspend(struct devfreq *devfreq);
+extern void devfreq_monitor_resume(struct devfreq *devfreq);
+extern void devfreq_interval_update(struct devfreq *devfreq,
+ unsigned int *delay);
+
+extern int devfreq_add_governor(struct devfreq_governor *governor);
+extern int devfreq_remove_governor(struct devfreq_governor *governor);
+
#endif /* _GOVERNOR_H */
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index af75ddd..db8ff77 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -26,14 +26,40 @@
return 0;
}
-static int performance_init(struct devfreq *devfreq)
+static int devfreq_performance_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
{
- return update_devfreq(devfreq);
+ int ret = 0;
+
+ if (event == DEVFREQ_GOV_START) {
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ }
+
+ return ret;
}
const struct devfreq_governor devfreq_performance = {
.name = "performance",
- .init = performance_init,
.get_target_freq = devfreq_performance_func,
- .no_central_polling = true,
+ .event_handler = devfreq_performance_handler,
};
+
+static int __init devfreq_performance_init(void)
+{
+ return devfreq_add_governor(&devfreq_performance);
+}
+subsys_initcall(devfreq_performance_init);
+
+static void __exit devfreq_performance_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_performance);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_performance_exit);
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index fec0cdb..30f0fca 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -23,14 +23,40 @@
return 0;
}
-static int powersave_init(struct devfreq *devfreq)
+static int devfreq_powersave_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
{
- return update_devfreq(devfreq);
+ int ret = 0;
+
+ if (event == DEVFREQ_GOV_START) {
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ }
+
+ return ret;
}
const struct devfreq_governor devfreq_powersave = {
.name = "powersave",
- .init = powersave_init,
.get_target_freq = devfreq_powersave_func,
- .no_central_polling = true,
+ .event_handler = devfreq_powersave_handler,
};
+
+static int __init devfreq_powersave_init(void)
+{
+ return devfreq_add_governor(&devfreq_powersave);
+}
+subsys_initcall(devfreq_powersave_init);
+
+static void __exit devfreq_powersave_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_powersave);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_powersave_exit);
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index a2e3eae..85f9ed5 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/devfreq.h>
#include <linux/math64.h>
+#include "governor.h"
/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
#define DFSO_UPTHRESHOLD (90)
@@ -88,7 +89,57 @@
return 0;
}
+static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ devfreq_monitor_start(devfreq);
+ break;
+
+ case DEVFREQ_GOV_STOP:
+ devfreq_monitor_stop(devfreq);
+ break;
+
+ case DEVFREQ_GOV_INTERVAL:
+ devfreq_interval_update(devfreq, (unsigned int *)data);
+ break;
+
+ case DEVFREQ_GOV_SUSPEND:
+ devfreq_monitor_suspend(devfreq);
+ break;
+
+ case DEVFREQ_GOV_RESUME:
+ devfreq_monitor_resume(devfreq);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
const struct devfreq_governor devfreq_simple_ondemand = {
.name = "simple_ondemand",
.get_target_freq = devfreq_simple_ondemand_func,
+ .event_handler = devfreq_simple_ondemand_handler,
};
+
+static int __init devfreq_simple_ondemand_init(void)
+{
+ return devfreq_add_governor(&devfreq_simple_ondemand);
+}
+subsys_initcall(devfreq_simple_ondemand_init);
+
+static void __exit devfreq_simple_ondemand_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_simple_ondemand);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_simple_ondemand_exit);
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 0681246..110f178 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -116,10 +116,45 @@
devfreq->data = NULL;
}
+static int devfreq_userspace_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ int ret = 0;
+
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ ret = userspace_init(devfreq);
+ break;
+ case DEVFREQ_GOV_STOP:
+ userspace_exit(devfreq);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
const struct devfreq_governor devfreq_userspace = {
.name = "userspace",
.get_target_freq = devfreq_userspace_func,
- .init = userspace_init,
- .exit = userspace_exit,
- .no_central_polling = true,
+ .event_handler = devfreq_userspace_handler,
};
+
+static int __init devfreq_userspace_init(void)
+{
+ return devfreq_add_governor(&devfreq_userspace);
+}
+subsys_initcall(devfreq_userspace_init);
+
+static void __exit devfreq_userspace_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_userspace);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_userspace_exit);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index 8c9b95d..48c2efb 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -55,7 +55,7 @@
cmd.permission_type = permission_type;
cmd.lock = SCM_CP_PROTECT;
- return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+ return scm_call(SCM_SVC_MP, SCM_CP_LOCK_CMD_ID,
&cmd, sizeof(cmd), NULL, 0);
}
@@ -68,7 +68,7 @@
cmd.permission_type = permission_type;
cmd.lock = SCM_CP_UNPROTECT;
- return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+ return scm_call(SCM_SVC_MP, SCM_CP_LOCK_CMD_ID,
&cmd, sizeof(cmd), NULL, 0);
}
@@ -154,7 +154,7 @@
request.chunks.chunk_list_size = nchunks;
request.chunks.chunk_size = chunk_size;
- return scm_call(SCM_SVC_CP, MEM_PROTECT_LOCK_ID,
+ return scm_call(SCM_SVC_MP, MEM_PROTECT_LOCK_ID,
&request, sizeof(request), &resp, sizeof(resp));
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 08c800e..8a409b6 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -52,8 +52,8 @@
0x2240, 0x227e,
0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
- 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
- 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
+ 0x22ff, 0x22ff, 0x2340, 0x2343,
+ 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
@@ -61,8 +61,8 @@
0x25f0, 0x25f0,
0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
- 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
- 0x2750, 0x2756, 0x2760, 0x2760, 0x300C, 0x300E, 0x301C, 0x301D,
+ 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,
+ 0x300C, 0x300E, 0x301C, 0x301D,
0x302A, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031, 0x3034, 0x3036,
0x303C, 0x303C, 0x305E, 0x305F,
};
@@ -2824,10 +2824,6 @@
{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
/* Set up VBIF_ROUND_ROBIN_QOS_ARB */
{ A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003 },
- /* Disable VBIF clock gating. This is to enable AXI running
- * higher frequency than GPU.
- */
- { A3XX_VBIF_CLKON, 1 },
{0, 0},
};
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 29cf0c1..44146a4 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -88,7 +88,7 @@
return 0;
of_node_put(np);
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_PTBL_SIZE, &spare,
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &spare,
sizeof(spare), psize, sizeof(psize));
if (ret) {
pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n");
@@ -111,7 +111,7 @@
pinit.paddr = virt_to_phys(buf);
pinit.size = psize[0];
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_PTBL_INIT, &pinit,
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &pinit,
sizeof(pinit), &ptbl_ret, sizeof(ptbl_ret));
if (ret) {
pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n");
@@ -142,7 +142,7 @@
cfg.id = sec_id;
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_CFG, &cfg, sizeof(cfg),
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_CFG, &cfg, sizeof(cfg),
&scm_ret, sizeof(scm_ret));
if (ret || scm_ret) {
pr_err("scm call IOMMU_SECURE_CFG failed\n");
@@ -167,7 +167,7 @@
map.info.va = va;
map.info.size = len;
- if (scm_call(SCM_SVC_CP, IOMMU_SECURE_MAP, &map, sizeof(map), &ret,
+ if (scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP, &map, sizeof(map), &ret,
sizeof(ret)))
return -EINVAL;
if (ret)
@@ -242,7 +242,7 @@
map.plist.size = SZ_1M;
}
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_MAP, &map, sizeof(map),
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP, &map, sizeof(map),
&scm_ret, sizeof(scm_ret));
kfree(pa_list);
return ret;
@@ -260,7 +260,7 @@
mi.va = va;
mi.size = len;
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_UNMAP, &mi, sizeof(mi),
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_UNMAP, &mi, sizeof(mi),
&scm_ret, sizeof(scm_ret));
return ret;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 52b7994..dce37e5 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -121,6 +121,7 @@
events->notified_index = 0;
events->bytes_read_no_event = 0;
events->current_event_data_size = 0;
+ events->wakeup_events_counter = 0;
}
static inline void dvb_dmxdev_flush_output(struct dvb_ringbuffer *buffer,
@@ -222,6 +223,10 @@
int new_write_index;
int data_event;
+ /* Check if the event is disabled */
+ if (events->event_mask.disable_mask & event->type)
+ return 0;
+
/* Check if we are adding an event that user already read its data */
if (events->bytes_read_no_event) {
data_event = 1;
@@ -241,7 +246,7 @@
if (data_event) {
if (res) {
/*
- * Data relevent to this event was fully
+ * Data relevant to this event was fully
* consumed already, discard event.
*/
events->bytes_read_no_event -= res;
@@ -266,6 +271,9 @@
events->queue[events->write_index] = *event;
events->write_index = new_write_index;
+ if (!(events->event_mask.no_wakeup_mask & event->type))
+ events->wakeup_events_counter++;
+
return 0;
}
@@ -280,6 +288,9 @@
events->notified_index =
dvb_dmxdev_advance_event_idx(events->notified_index);
+ if (!(events->event_mask.no_wakeup_mask & event->type))
+ events->wakeup_events_counter--;
+
return 0;
}
@@ -291,6 +302,13 @@
int data_event;
/*
+ * If data events are not enabled on this filter,
+ * there's nothing to update.
+ */
+ if (events->data_read_event_masked)
+ return 0;
+
+ /*
* Go through all events that were notified and
* remove them from the events queue if their respective
* data was read.
@@ -364,7 +382,7 @@
if (data_event) {
if (res) {
/*
- * Data relevent to this event was
+ * Data relevant to this event was
* fully consumed, remove it from the queue.
*/
bytes_read -= res;
@@ -616,6 +634,9 @@
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
+ dmxdev->dvr_output_events.event_mask.disable_mask = 0;
+ dmxdev->dvr_output_events.event_mask.no_wakeup_mask = 0;
+ dmxdev->dvr_output_events.event_mask.wakeup_threshold = 1;
dmxdev->dvr_feeds_count = 0;
dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
dmxdev->dvr_priv_buff_handle = NULL;
@@ -1429,24 +1450,58 @@
static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter,
int cookie)
{
- if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
- (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) {
- struct dmxdev_feed *feed;
- int ret = -ENODEV;
+ struct dmxdev_feed *feed;
- /* Only one feed should be in the list in case of decoder */
- feed = list_first_entry(&dmxdevfilter->feed.ts,
- struct dmxdev_feed, next);
+ if ((dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ (dmxdevfilter->params.pes.output != DMX_OUT_DECODER) ||
+ (dmxdevfilter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_ES_DATA))
+ return -EPERM;
- if (feed->ts->reuse_decoder_buffer)
- ret = feed->ts->reuse_decoder_buffer(
- feed->ts,
- cookie);
+ /* Only one feed should be in the list in case of decoder */
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
- return ret;
- }
+ if (feed->ts->reuse_decoder_buffer)
+ return feed->ts->reuse_decoder_buffer(feed->ts, cookie);
- return -EPERM;
+ return -ENODEV;
+}
+
+static int dvb_dmxdev_set_event_mask(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_events_mask *event_mask)
+{
+ if (!event_mask ||
+ (event_mask->wakeup_threshold >= DMX_EVENT_QUEUE_SIZE))
+ return -EINVAL;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ /*
+ * Overflow event is not allowed to be masked.
+ * This is because if overflow occurs, demux stops outputting data
+ * until user is notified. If user is using events to read the data,
+ * the overflow event must be always enabled or otherwise we would
+ * never recover from overflow state.
+ */
+ event_mask->disable_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW;
+ event_mask->no_wakeup_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW;
+
+ dmxdevfilter->events.event_mask = *event_mask;
+
+ return 0;
+}
+
+static int dvb_dmxdev_get_event_mask(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_events_mask *event_mask)
+{
+ if (!event_mask)
+ return -EINVAL;
+
+ *event_mask = dmxdevfilter->events.event_mask;
+
+ return 0;
}
static int dvb_dmxdev_ts_fullness_callback(
@@ -1708,11 +1763,13 @@
}
/*
- * Decoder filters have no data in the data buffer and their
- * events can be removed now from the queue.
+ * If no-data events are enabled on this filter,
+ * the events can be removed from the queue when
+ * user gets them.
+ * For filters with data events enabled, the event is removed
+ * from the queue only when the respective data is read.
*/
- if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
- (dmxdevfilter->params.pes.output == DMX_OUT_DECODER))
+ if (dmxdevfilter->events.data_read_event_masked)
dmxdevfilter->events.read_index =
dvb_dmxdev_advance_event_idx(
dmxdevfilter->events.read_index);
@@ -2538,6 +2595,9 @@
(*secfilter)->filter_mask[2] = 0;
filter->todo = 0;
+ filter->events.data_read_event_masked =
+ filter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_SECTION;
ret = filter->feed.sec.feed->start_filtering(
filter->feed.sec.feed);
@@ -2558,6 +2618,21 @@
filter->params.pes.rec_chunk_size =
filter->buffer.size >> 2;
+ if (filter->params.pes.output == DMX_OUT_TS_TAP)
+ dmxdev->dvr_output_events.data_read_event_masked =
+ dmxdev->dvr_output_events.event_mask.disable_mask &
+ DMX_EVENT_NEW_REC_CHUNK;
+ else if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ filter->events.data_read_event_masked =
+ filter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_REC_CHUNK;
+ else if (filter->params.pes.output == DMX_OUT_TAP)
+ filter->events.data_read_event_masked =
+ filter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_PES;
+ else
+ filter->events.data_read_event_masked = 1;
+
ret = 0;
list_for_each_entry(feed, &filter->feed.ts, next) {
ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
@@ -2627,6 +2702,9 @@
dmxdevfilter->priv_buff_handle = NULL;
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dvb_dmxdev_flush_events(&dmxdevfilter->events);
+ dmxdevfilter->events.event_mask.disable_mask = DMX_EVENT_NEW_ES_DATA;
+ dmxdevfilter->events.event_mask.no_wakeup_mask = 0;
+ dmxdevfilter->events.event_mask.wakeup_threshold = 1;
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
@@ -3223,6 +3301,24 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_EVENTS_MASK:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_event_mask(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_GET_EVENTS_MASK:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_event_mask(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -3258,10 +3354,9 @@
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (POLLIN | POLLRDNORM);
- if (dmxdevfilter->events.notified_index !=
- dmxdevfilter->events.write_index) {
+ if (dmxdevfilter->events.wakeup_events_counter >=
+ dmxdevfilter->events.event_mask.wakeup_threshold)
mask |= POLLPRI;
- }
return mask;
}
@@ -3430,8 +3525,8 @@
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM);
- if (dmxdev->dvr_output_events.notified_index !=
- dmxdev->dvr_output_events.write_index)
+ if (dmxdev->dvr_output_events.wakeup_events_counter >=
+ dmxdev->dvr_output_events.event_mask.wakeup_threshold)
mask |= POLLPRI;
} else {
poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index a55b4f0..1443de5 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -68,8 +68,8 @@
struct dmx_section_feed *feed;
};
-struct dmxdev_events_queue {
#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
+struct dmxdev_events_queue {
/*
* indices used to manage events queue.
* read_index advanced when relevent data is read
@@ -94,6 +94,22 @@
u32 current_event_data_size;
u32 current_event_start_offset;
+ /* current setting of the events masking */
+ struct dmx_events_mask event_mask;
+
+ /*
+ * indicates if an event used for data-reading from demux
+ * filter is enabled or not. These are events on which
+ * user may wait for before calling read() on the demux filter.
+ */
+ int data_read_event_masked;
+
+ /*
+ * holds the current number of pending events in the
+ * events queue that are considered as a wake-up source
+ */
+ u32 wakeup_events_counter;
+
struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
};
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 6418f21..fbc2b93 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -355,7 +355,7 @@
if (WARN_ON(!msm_subdev))
return -EINVAL;
- if (WARN_ON(!msm_v4l2_dev) && WARN_ON(!msm_v4l2_dev->dev))
+ if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
return -EIO;
return __msm_sd_register_subdev(&msm_subdev->sd);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 499b36c..9be4704 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -75,10 +75,6 @@
module_param(video_nonsecure_ion_heap, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(video_nonsecure_ion_heap, "ION heap for non-secure video buffer allocation");
-static int generate_es_events;
-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);
@@ -1224,13 +1220,6 @@
{
struct mpq_demux *mpq_demux = feed->demux->priv;
- if (!generate_es_events) {
- MPQ_DVB_ERR_PRINT(
- "%s: Cannot release decoder buffer when not working with new elementary stream data events\n",
- __func__);
- return -EPERM;
- }
-
if (cookie < 0) {
MPQ_DVB_ERR_PRINT("%s: invalid cookie parameter\n", __func__);
return -EINVAL;
@@ -2834,13 +2823,11 @@
__func__);
}
- if (generate_es_events) {
- mpq_dmx_prepare_es_event_data(
- &packet, &meta_data, feed_data,
- stream_buffer, &data);
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data, feed_data,
+ stream_buffer, &data);
- feed->data_ready_cb.ts(&feed->feed.ts, &data);
- }
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
feed_data->pending_pattern_len = 0;
mpq_streambuffer_get_data_rw_offset(
@@ -2975,15 +2962,13 @@
NULL,
&feed_data->frame_offset);
- if (generate_es_events) {
- mpq_dmx_prepare_es_event_data(
- &packet, &meta_data,
- feed_data,
- stream_buffer, &data);
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data,
+ feed_data,
+ stream_buffer, &data);
- feed->data_ready_cb.ts(
- &feed->feed.ts, &data);
- }
+ feed->data_ready_cb.ts(
+ &feed->feed.ts, &data);
} else {
MPQ_DVB_ERR_PRINT(
"%s: received PUSI"
@@ -4122,6 +4107,8 @@
int ret;
int pes_cnt = 0;
struct dmx_data_ready data_event;
+ struct dmx_data_ready data;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
goto decoder_filter_check_overflow;
@@ -4249,15 +4236,11 @@
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);
- }
+ 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);
}
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index f8460be..40e09b6 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1165,6 +1165,16 @@
sizeof(struct hfi_index_extradata_config);
break;
}
+ case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hal_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
case HAL_CONFIG_VPE_DEINTERLACE:
break;
/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
@@ -1187,7 +1197,6 @@
case HAL_PARAM_VDEC_MB_QUANTIZATION:
case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
- case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
case HAL_CONFIG_VDEC_MULTI_STREAM:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index be9458d..102e1ec 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -305,11 +305,213 @@
callback(RELEASE_RESOURCE_DONE, &cmd_done);
}
+static inline void copy_cap_prop(
+ struct hfi_capability_supported *in,
+ struct vidc_hal_session_init_done *sess_init_done)
+{
+ struct hal_capability_supported *out = NULL;
+ switch (in->capability_type) {
+ case HFI_CAPABILITY_FRAME_WIDTH:
+ out = &sess_init_done->width;
+ break;
+
+ case HFI_CAPABILITY_FRAME_HEIGHT:
+ out = &sess_init_done->height;
+ break;
+
+ case HFI_CAPABILITY_MBS_PER_FRAME:
+ out = &sess_init_done->mbs_per_frame;
+ break;
+
+ case HFI_CAPABILITY_MBS_PER_SECOND:
+ out = &sess_init_done->mbs_per_sec;
+ break;
+
+ case HFI_CAPABILITY_FRAMERATE:
+ out = &sess_init_done->frame_rate;
+ break;
+
+ case HFI_CAPABILITY_SCALE_X:
+ out = &sess_init_done->scale_x;
+ break;
+
+ case HFI_CAPABILITY_SCALE_Y:
+ out = &sess_init_done->scale_y;
+ break;
+
+ case HFI_CAPABILITY_BITRATE:
+ out = &sess_init_done->bitrate;
+ break;
+ }
+
+ if (in && out) {
+ out->capability_type =
+ (enum hal_capability)in->capability_type;
+ out->min = in->min;
+ out->max = in->max;
+ out->step_size = in->step_size;
+ }
+}
+
enum vidc_status hfi_process_sess_init_done_prop_read(
struct hfi_msg_sys_session_init_done_packet *pkt,
- struct msm_vidc_cb_cmd_done *cmddone)
+ struct vidc_hal_session_init_done *sess_init_done)
{
- return VIDC_ERR_NONE;
+ u32 rem_bytes, num_properties;
+ u8 *data_ptr;
+ u32 status = VIDC_ERR_NONE;
+ u32 prop_id, next_offset = 0;
+
+ rem_bytes = pkt->size - sizeof(struct
+ hfi_msg_sys_session_init_done_packet) + sizeof(u32);
+
+ if (rem_bytes == 0) {
+ dprintk(VIDC_ERR,
+ "hfi_msg_sys_session_init_done:missing_prop_info");
+ return VIDC_ERR_FAIL;
+ }
+
+ status = hfi_map_err_status((u32)pkt->error_type);
+
+ if (status)
+ return status;
+
+ data_ptr = (u8 *) &pkt->rg_property_data[0];
+ num_properties = pkt->num_properties;
+
+ while ((status == VIDC_ERR_NONE) && num_properties &&
+ (rem_bytes >= sizeof(u32))) {
+ prop_id = *((u32 *)data_ptr);
+ next_offset = sizeof(u32);
+
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
+ {
+ struct hfi_capability_supported_info *prop =
+ (struct hfi_capability_supported_info *)
+ (data_ptr + next_offset);
+ u32 num_capabilities;
+ struct hfi_capability_supported *cap_ptr;
+
+ if ((rem_bytes - next_offset) < sizeof(*cap_ptr)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+
+ num_capabilities = prop->num_capabilities;
+ cap_ptr = &prop->rg_data[0];
+ next_offset += sizeof(u32);
+
+ while (num_capabilities &&
+ ((rem_bytes - next_offset) >= sizeof(u32))) {
+ copy_cap_prop(cap_ptr, sess_init_done);
+ cap_ptr++;
+ next_offset += sizeof(*cap_ptr);
+ num_capabilities--;
+ }
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ {
+ struct hfi_uncompressed_format_supported *prop =
+ (struct hfi_uncompressed_format_supported *)
+ (data_ptr + next_offset);
+
+ u32 num_format_entries;
+ char *fmt_ptr;
+ struct hfi_uncompressed_plane_info *plane_info;
+
+ if ((rem_bytes - next_offset) < sizeof(*prop)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ num_format_entries = prop->format_entries;
+ next_offset = sizeof(*prop) - sizeof(u32);
+ fmt_ptr = (char *)&prop->rg_format_info[0];
+
+ while (num_format_entries) {
+ u32 bytes_to_skip;
+ plane_info =
+ (struct hfi_uncompressed_plane_info *) fmt_ptr;
+
+ if ((rem_bytes - next_offset) <
+ sizeof(*plane_info)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ bytes_to_skip = sizeof(*plane_info) -
+ sizeof(struct
+ hfi_uncompressed_plane_constraints) +
+ plane_info->num_planes *
+ sizeof(struct
+ hfi_uncompressed_plane_constraints);
+
+ fmt_ptr += bytes_to_skip;
+ next_offset += bytes_to_skip;
+ num_format_entries--;
+ }
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED:
+ {
+ struct hfi_properties_supported *prop =
+ (struct hfi_properties_supported *)
+ (data_ptr + next_offset);
+
+ next_offset += sizeof(*prop) - sizeof(u32)
+ + prop->num_properties * sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
+ {
+ struct hfi_profile_level_supported *prop =
+ (struct hfi_profile_level_supported *)
+ (data_ptr + next_offset);
+
+ next_offset += sizeof(*prop) -
+ sizeof(struct hfi_profile_level) +
+ prop->profile_count *
+ sizeof(struct hfi_profile_level);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ {
+ next_offset +=
+ sizeof(struct hfi_nal_stream_format_supported);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT:
+ {
+ next_offset += sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ {
+ next_offset += sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH:
+ {
+ next_offset +=
+ sizeof(struct hfi_intra_refresh);
+ num_properties--;
+ break;
+ }
+ default:
+ dprintk(VIDC_DBG,
+ "%s default case - 0x%x", __func__, prop_id);
+ }
+ rem_bytes -= next_offset;
+ data_ptr += next_offset;
+ }
+ return status;
}
static void hfi_process_sess_get_prop_buf_req(
@@ -493,7 +695,7 @@
cmd_done.data = &session_init_done;
if (!cmd_done.status) {
cmd_done.status = hfi_process_sess_init_done_prop_read(
- pkt, &cmd_done);
+ pkt, &session_init_done);
}
cmd_done.size = sizeof(struct vidc_hal_session_init_done);
callback(SESSION_INIT_DONE, &cmd_done);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 663cc40..d782227 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -682,6 +682,13 @@
{
return 0;
}
+
+static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
+}
static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -703,7 +710,8 @@
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
.vidioc_s_parm = msm_v4l2_s_parm,
- .vidioc_g_parm = msm_v4l2_g_parm
+ .vidioc_g_parm = msm_v4l2_g_parm,
+ .vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 5966d12..8f8e723 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -20,10 +20,6 @@
#include "msm_vidc_debug.h"
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
-#define DEFAULT_HEIGHT 720
-#define DEFAULT_WIDTH 1280
-#define MAX_SUPPORTED_WIDTH 3820
-#define MAX_SUPPORTED_HEIGHT 2160
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS 6
@@ -248,7 +244,7 @@
return (MAX_SUPPORTED_WIDTH * MAX_SUPPORTED_HEIGHT * 3/2)/2;
}
-static const struct msm_vidc_format vdec_formats[] = {
+struct msm_vidc_format vdec_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
@@ -582,7 +578,6 @@
int stride, scanlines;
int extra_idx = 0;
int rc = 0;
- int ret;
int i;
struct hal_buffer_requirements *buff_req_buffer;
if (!inst || !f || !inst->core || !inst->core->device) {
@@ -602,6 +597,12 @@
if (inst->in_reconfig == true) {
inst->prop.height = inst->reconfig_height;
inst->prop.width = inst->reconfig_width;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
}
f->fmt.pix_mp.height = inst->prop.height;
f->fmt.pix_mp.width = inst->prop.width;
@@ -612,10 +613,20 @@
frame_sz.height = inst->prop.height;
dprintk(VIDC_DBG, "width = %d, height = %d\n",
frame_sz.width, frame_sz.height);
- ret = msm_comm_try_set_prop(inst,
+ rc = msm_comm_try_set_prop(inst,
HAL_PARAM_FRAME_SIZE, &frame_sz);
- ret = ret || msm_comm_try_get_bufreqs(inst);
- if (ret || (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed : Frame size setting\n", __func__);
+ goto exit;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed : Buffer requirements\n", __func__);
+ goto exit;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
fmt->get_frame_size(i,
@@ -680,6 +691,7 @@
f->type);
rc = -EINVAL;
}
+exit:
return rc;
}
int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
@@ -717,7 +729,7 @@
}
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
- const struct msm_vidc_format *fmt = NULL;
+ struct msm_vidc_format *fmt = NULL;
struct hal_frame_size frame_sz;
int extra_idx = 0;
int rc = 0;
@@ -787,6 +799,12 @@
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
inst->prop.width = f->fmt.pix_mp.width;
inst->prop.height = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_invalid_fmt;
+ }
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats),
f->fmt.pix_mp.pixelformat,
@@ -1161,6 +1179,10 @@
inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
inst->prop.height = DEFAULT_HEIGHT;
inst->prop.width = DEFAULT_WIDTH;
+ inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+ inst->capability.height.max = DEFAULT_HEIGHT;
+ inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+ inst->capability.width.max = DEFAULT_WIDTH;
inst->prop.fps = 30;
inst->prop.prev_time_stamp = 0;
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 072f4ab..9aa8175 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -19,10 +19,7 @@
#include "msm_vidc_debug.h"
#define MSM_VENC_DVC_NAME "msm_venc_8974"
-#define DEFAULT_HEIGHT 720
-#define DEFAULT_WIDTH 1280
#define MIN_NUM_OUTPUT_BUFFERS 4
-#define MAX_NUM_OUTPUT_BUFFERS 8
#define MIN_BIT_RATE 64000
#define MAX_BIT_RATE 160000000
#define DEFAULT_BIT_RATE 64000
@@ -88,6 +85,27 @@
"High Latency",
};
+static const char *const mpeg_video_vidc_extradata[] = {
+ "Extradata none",
+ "Extradata MB Quantization",
+ "Extradata Interlace Video",
+ "Extradata VC1 Framedisp",
+ "Extradata VC1 Seqdisp",
+ "Extradata timestamp",
+ "Extradata S3D Frame Packing",
+ "Extradata Frame Rate",
+ "Extradata Panscan Window",
+ "Extradata Recovery point SEI",
+ "Extradata Closed Caption UD",
+ "Extradata AFD UD",
+ "Extradata Multislice info",
+ "Extradata number of concealed MB",
+ "Extradata metadata filler",
+ "Extradata input crop",
+ "Extradata digital zoom",
+ "Extradata aspect ratio",
+};
+
enum msm_venc_ctrl_cluster {
MSM_VENC_CTRL_CLUSTER_QP = 1,
MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
@@ -439,6 +457,18 @@
.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE,
+ .name = "Slice delivery mode",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .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,
@@ -557,6 +587,36 @@
.qmenu = NULL,
.cluster = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+ .name = "Extradata Type",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+ .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_AFD_UD) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
+ ),
+ .qmenu = mpeg_video_vidc_extradata,
+ .step = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -578,7 +638,7 @@
return sz;
}
-static const struct msm_vidc_format venc_formats[] = {
+static struct msm_vidc_format venc_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
@@ -640,6 +700,9 @@
struct hal_buffer_count_actual new_buf_count;
enum hal_property property_id;
struct hfi_device *hdev;
+ struct hal_buffer_requirements *buff_req;
+ struct v4l2_ctrl *ctrl = NULL;
+ u32 extradata = 0;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
@@ -655,13 +718,33 @@
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
*num_planes = 1;
- if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
- *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
- *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ *num_buffers = buff_req->buffer_count_actual =
+ max(*num_buffers, buff_req->buffer_count_actual);
+ if (*num_buffers > VIDEO_MAX_FRAME) {
+ dprintk(VIDC_ERR,
+ "Failed : No of slices requested = %d"\
+ " Max supported slices = %d",
+ *num_buffers, VIDEO_MAX_FRAME);
+ rc = -EINVAL;
+ break;
+ }
+ ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+ if (ctrl)
+ extradata = v4l2_ctrl_g_ctrl(ctrl);
+ if (extradata)
+ *num_planes = *num_planes + 1;
+ inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
for (i = 0; i < *num_planes; i++) {
sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = call_hfi_op(hdev, session_set_property, inst->session,
+ property_id, &new_buf_count);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
@@ -1342,6 +1425,25 @@
multi_slice_control.slice_size = ctrl->val;
pdata = &multi_slice_control;
break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+ if ((temp_ctrl->val ==
+ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) &&
+ (inst->fmts[CAPTURE_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264 ||
+ inst->fmts[CAPTURE_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264_NO_SC)) {
+ property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
+ enable.enable = true;
+ } else {
+ dprintk(VIDC_WARN,
+ "Failed : slice delivery mode is valid "\
+ "only for H264 encoder and MB based slicing");
+ enable.enable = false;
+ }
+ pdata = &enable;
+ break;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
@@ -1452,6 +1554,15 @@
inst->mode = VIDC_SECURE;
dprintk(VIDC_INFO, "Setting secure mode to :%d\n", inst->mode);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+ {
+ struct hal_extradata_enable extra;
+ property_id = HAL_PARAM_INDEX_EXTRADATA;
+ extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+ extra.enable = 1;
+ pdata = &extra;
+ break;
+ }
default:
rc = -ENOTSUPP;
break;
@@ -1676,7 +1787,7 @@
}
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
- const struct msm_vidc_format *fmt = NULL;
+ struct msm_vidc_format *fmt = NULL;
struct hal_frame_size frame_sz;
int rc = 0;
int i;
@@ -1707,6 +1818,12 @@
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
inst->prop.width = f->fmt.pix_mp.width;
inst->prop.height = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->prop.width;
frame_sz.height = inst->prop.height;
@@ -1768,6 +1885,7 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
int i;
+ int extra_idx = 0;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -1788,6 +1906,16 @@
fmt->get_frame_size(i, inst->prop.height,
inst->prop.width);
}
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ inst->buff_req.buffer
+ [HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ }
+ for (i = 0; i < fmt->num_planes; ++i) {
+ inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
} else {
dprintk(VIDC_ERR,
"Buf type not recognized, type = %d\n", f->type);
@@ -1827,6 +1955,7 @@
int i;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
+ int extra_idx = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1839,24 +1968,41 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG,
- "device_addr = %ld, size = %d\n",
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+
+ for (i = 0; (i < b->length) && (i < VIDEO_MAX_PLANES); i++) {
+ dprintk(VIDC_DBG, "device_addr = 0x%lx, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
- rc = call_hfi_op(hdev, session_set_buffers,
- (void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
- "vidc_hal_session_set_buffers failed");
}
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ dprintk(VIDC_DBG, "extradata: 0x%lx\n",
+ b->m.planes[extra_idx].m.userptr);
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
+ }
+
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed");
break;
default:
dprintk(VIDC_ERR,
@@ -1869,8 +2015,7 @@
int msm_venc_release_buf(struct msm_vidc_inst *inst,
struct v4l2_buffer *b)
{
- int rc = 0;
- int i;
+ int i, rc = 0, extra_idx = 0;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
@@ -1891,24 +2036,36 @@
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ if (b->length !=
+ inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
for (i = 0; i < b->length; i++) {
dprintk(VIDC_DBG,
- "Release device_addr = %ld, size = %d, %d\n",
+ "Release device_addr = 0x%lx, size = %d, %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length, inst->state);
- buffer_info.buffer_size = b->m.planes[i].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
- buffer_info.response_required = false;
- rc = call_hfi_op(hdev, session_release_buffers,
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
+ if (rc)
+ dprintk(VIDC_ERR,
"vidc_hal_session_release_buffers failed\n");
}
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 218987e..0fbfd72 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -299,6 +299,30 @@
return -EINVAL;
}
+
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_core_capability *capability = NULL;
+
+ if (!inst || !fsize) {
+ dprintk(VIDC_ERR, "%s: invalid parameter: %p %p\n",
+ __func__, inst, fsize);
+ return -EINVAL;
+ }
+ if (!inst->core)
+ return -EINVAL;
+
+ capability = &inst->capability;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = capability->width.min;
+ fsize->stepwise.max_width = capability->width.max;
+ fsize->stepwise.step_width = capability->width.step_size;
+ fsize->stepwise.min_height = capability->height.min;
+ fsize->stepwise.max_height = capability->height.max;
+ fsize->stepwise.step_height = capability->height.step_size;
+ return 0;
+}
static void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index ba3e393..4346a4e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -174,8 +174,8 @@
}
return &fmt[i];
}
-const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
- const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
{
int i;
if (!fmt) {
@@ -350,7 +350,15 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
if (response) {
+ struct vidc_hal_session_init_done *session_init_done =
+ (struct vidc_hal_session_init_done *) response->data;
inst = (struct msm_vidc_inst *)response->session_id;
+
+ inst->capability.width = session_init_done->width;
+ inst->capability.height = session_init_done->height;
+ inst->capability.frame_rate =
+ session_init_done->frame_rate;
+ inst->capability.capability_set = true;
signal_session_msg_receipt(cmd, inst);
} else {
dprintk(VIDC_ERR,
@@ -394,8 +402,11 @@
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ rc = msm_vidc_check_session_supported(inst);
+ if (!rc) {
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
+ }
return;
} else {
dprintk(VIDC_ERR,
@@ -1789,6 +1800,13 @@
mutex_unlock(&inst->sync_lock);
} else {
int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
+
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_no_mem;
+ }
do_div(time_usec, NSEC_PER_USEC);
memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
frame_data.alloc_len = vb->v4l2_planes[0].length;
@@ -2359,3 +2377,54 @@
hdev->hfi_device_data, type);
return rc;
}
+
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core_capability *capability;
+ int rc = 0;
+ struct v4l2_event dqevent;
+
+ if (!inst) {
+ dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+ capability = &inst->capability;
+
+ if (inst->capability.capability_set) {
+ if (msm_vp8_low_tier &&
+ inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
+ capability->width.max = DEFAULT_WIDTH;
+ capability->height.max = DEFAULT_HEIGHT;
+ }
+ if (inst->prop.width < capability->width.min ||
+ inst->prop.width > capability->width.max ||
+ (inst->prop.width % capability->width.step_size != 0)) {
+ dprintk(VIDC_ERR,
+ "Unsupported width = %d range min(%u) - max(%u) step_size(%u)",
+ inst->prop.width, capability->width.min,
+ capability->width.max, capability->width.step_size);
+ rc = -ENOTSUPP;
+ }
+
+ if (inst->prop.height < capability->height.min ||
+ inst->prop.height > capability->height.max ||
+ (inst->prop.height %
+ capability->height.step_size != 0)) {
+ dprintk(VIDC_ERR,
+ "Unsupported height = %d range min(%u) - max(%u) step_size(%u)",
+ inst->prop.height, capability->height.min,
+ capability->height.max, capability->height.step_size);
+ rc = -ENOTSUPP;
+ }
+ }
+ if (rc) {
+ mutex_lock(&inst->sync_lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->sync_lock);
+ dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+ dqevent.id = 0;
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
+ }
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 4f3deb6..862dfab 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -21,8 +21,8 @@
struct msm_vidc_core *get_vidc_core(int core_id);
const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
-const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
- const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
struct buf_queue *msm_comm_get_vb2q(
struct msm_vidc_inst *inst, enum v4l2_buf_type type);
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 62158b0..5948c7c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -18,7 +18,8 @@
int msm_vidc_debug = 0x3;
int msm_fw_debug = 0x18;
int msm_fw_debug_mode = 0x1;
-int msm_fw_low_power_mode = 0x0;
+int msm_fw_low_power_mode = 0x1;
+int msm_vp8_low_tier = 0x1;
struct debug_buffer {
char ptr[MAX_DBG_BUF_SIZE];
@@ -165,6 +166,11 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ if (!debugfs_create_u32("vp8_low_tier", S_IRUGO | S_IWUSR,
+ parent, &msm_vp8_low_tier)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
failed_create_dir:
return dir;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index fb06af6..ea6dd70 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -45,6 +45,7 @@
extern int msm_fw_debug;
extern int msm_fw_debug_mode;
extern int msm_fw_low_power_mode;
+extern int msm_vp8_low_tier;
#define dprintk(__level, __fmt, arg...) \
do { \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 8238d42..1bfbaa6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -37,6 +37,14 @@
#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
#define MAX_DEBUGFS_NAME 50
#define DEFAULT_TIMEOUT 3
+#define DEFAULT_HEIGHT 1080
+#define DEFAULT_WIDTH 1920
+#define MIN_SUPPORTED_WIDTH 32
+#define MIN_SUPPORTED_HEIGHT 32
+#define MAX_SUPPORTED_WIDTH 3820
+#define MAX_SUPPORTED_HEIGHT 2160
+
+
#define V4L2_EVENT_VIDC_BASE 10
@@ -166,6 +174,13 @@
VIDC_SECURE,
};
+struct msm_vidc_core_capability {
+ struct hal_capability_supported width;
+ struct hal_capability_supported height;
+ struct hal_capability_supported frame_rate;
+ u32 capability_set;
+};
+
struct msm_vidc_core {
struct list_head list;
struct mutex sync_lock, lock;
@@ -189,7 +204,7 @@
void *session;
struct session_prop prop;
int state;
- const struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct msm_vidc_format *fmts[MAX_PORT_NUM];
struct buf_queue bufq[MAX_PORT_NUM];
struct list_head pendingq;
struct list_head internalbufs;
@@ -212,6 +227,7 @@
struct msm_vidc_debug debug;
struct buf_count count;
enum msm_vidc_mode mode;
+ struct msm_vidc_core_capability capability;
};
extern struct msm_vidc_drv *vidc_driver;
@@ -238,4 +254,5 @@
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);
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
#endif
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 232ad90..995c655 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2604,7 +2604,7 @@
}
}
- rc = scm_call(SCM_SVC_CP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
+ rc = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
sizeof(memprot), &resp, sizeof(resp));
if (rc)
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 9fb7c6d..3d11400 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -271,11 +271,15 @@
mmap_context.ion_client = wfd_dev->ion_client;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENC_MMAP, &mmap_context);
- if (rc || !enc_mregion->paddr) {
+ if (rc) {
WFD_MSG_ERR("Failed to map input memory\n");
goto alloc_fail;
+ } else if (!enc_mregion->paddr) {
+ WFD_MSG_ERR("ENC_MMAP returned success" \
+ "but failed to map input memory\n");
+ rc = -EINVAL;
+ goto alloc_fail;
}
-
WFD_MSG_DBG("NOTE: enc paddr = [%p->%p], kvaddr = %p\n",
enc_mregion->paddr, (int8_t *)
enc_mregion->paddr + enc_mregion->size,
@@ -303,7 +307,7 @@
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_MMAP, (void *)&mmap_context);
- if (rc || !mdp_mregion->paddr) {
+ if (rc) {
WFD_MSG_ERR(
"Failed to map to mdp, rc = %d, paddr = 0x%p\n",
rc, mdp_mregion->paddr);
@@ -311,6 +315,14 @@
mdp_mregion->paddr = NULL;
mdp_mregion->ion_handle = NULL;
goto mdp_mmap_fail;
+ } else if (!mdp_mregion->paddr) {
+ WFD_MSG_ERR("MDP_MMAP returned success" \
+ "but failed to map to MDP\n");
+ rc = -EINVAL;
+ mdp_mregion->kvaddr = NULL;
+ mdp_mregion->paddr = NULL;
+ mdp_mregion->ion_handle = NULL;
+ goto mdp_mmap_fail;
}
mdp_buf.inst = inst->mdp_inst;
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index f7e8c9f..c37a4a4 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * 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
@@ -2264,19 +2264,22 @@
*/
bam.manage = SPS_BAM_MGR_DEVICE_REMOTE | SPS_BAM_MGR_MULTI_EE;
+ rc = sps_phy2h(bam.phys_addr, &nand_info->sps.bam_handle);
+ if (!rc)
+ goto init_sps_ep;
rc = sps_register_bam_device(&bam, &nand_info->sps.bam_handle);
if (rc) {
- pr_err("sps_register_bam_device() failed with %d\n", rc);
+ pr_err("%s: sps_register_bam_device() failed with %d\n",
+ __func__, rc);
goto out;
}
- pr_info("BAM device registered: bam_handle 0x%x\n",
- nand_info->sps.bam_handle);
-
+ pr_info("%s: BAM device registered: bam_handle 0x%x\n",
+ __func__, nand_info->sps.bam_handle);
+init_sps_ep:
rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.data_prod,
SPS_DATA_PROD_PIPE_INDEX);
if (rc)
- goto unregister_bam;
-
+ goto out;
rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.data_cons,
SPS_DATA_CONS_PIPE_INDEX);
if (rc)
@@ -2291,22 +2294,20 @@
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_cons);
deinit_data_prod:
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_prod);
-unregister_bam:
- sps_deregister_bam_device(nand_info->sps.bam_handle);
out:
return rc;
}
/*
- * This function de-registers BAM device, disconnects and frees its end points
- * for all the pipes.
+ * This function disconnects and frees its end points for all the pipes.
+ * Since the BAM is shared resource, it is not deregistered as its handle
+ * might be in use with LCDC.
*/
static void msm_nand_bam_free(struct msm_nand_info *nand_info)
{
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_prod);
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_cons);
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.cmd_pipe);
- sps_deregister_bam_device(nand_info->sps.bam_handle);
}
/* This function enables DMA support for the NANDc in BAM mode. */
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index e5aca6f..b48785c 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -535,6 +535,7 @@
static int dwc3_msm_dbm_ep_unconfig(u8 usb_ep)
{
u8 dbm_ep;
+ u32 data;
dev_dbg(context->dev, "%s\n", __func__);
@@ -548,10 +549,18 @@
context->ep_num_mapping[dbm_ep] = 0;
- dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep), 0);
+ data = dwc3_msm_read_reg(context->base, DBM_EP_CFG(dbm_ep));
+ data &= (~0x1);
+ dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep), data);
/* Reset the dbm endpoint */
dwc3_msm_dbm_ep_soft_reset(dbm_ep, true);
+ /*
+ * 10 usec delay is required before deasserting DBM endpoint reset
+ * according to hardware programming guide.
+ */
+ udelay(10);
+ dwc3_msm_dbm_ep_soft_reset(dbm_ep, false);
return 0;
}
@@ -888,6 +897,8 @@
}
(*new_ep_ops) = (*ep->ops);
new_ep_ops->queue = dwc3_msm_ep_queue;
+ new_ep_ops->disable = ep->ops->disable;
+
ep->ops = new_ep_ops;
/*
@@ -1328,24 +1339,27 @@
dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
}
-static void dwc3_msm_block_reset(void)
+static void dwc3_msm_block_reset(bool core_reset)
{
+
struct dwc3_msm *mdwc = context;
int ret = 0;
- ret = dwc3_msm_link_clk_reset(1);
- if (ret)
- return;
+ if (core_reset) {
+ ret = dwc3_msm_link_clk_reset(1);
+ if (ret)
+ return;
- usleep_range(1000, 1200);
- ret = dwc3_msm_link_clk_reset(0);
- if (ret)
- return;
+ usleep_range(1000, 1200);
+ ret = dwc3_msm_link_clk_reset(0);
+ if (ret)
+ return;
- usleep_range(10000, 12000);
+ usleep_range(10000, 12000);
- /* Reinitialize QSCRATCH registers after block reset */
- dwc3_msm_qscratch_reg_init(mdwc);
+ /* Reinitialize QSCRATCH registers after block reset */
+ dwc3_msm_qscratch_reg_init(mdwc);
+ }
/* Reset the DBM */
dwc3_msm_dbm_soft_reset(1);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 01fad76..282f49e 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -206,6 +206,20 @@
return ret;
}
dwc3_otg_notify_host_mode(otg, on);
+
+ /*
+ * Perform USB hardware RESET (both core reset and DBM reset)
+ * when moving from host to peripheral. This is required for
+ * peripheral mode to work.
+ */
+ if (ext_xceiv && ext_xceiv->otg_capability &&
+ ext_xceiv->ext_block_reset)
+ ext_xceiv->ext_block_reset(true);
+
+ /* re-init core and OTG registers as block reset clears these */
+ dwc3_post_host_reset_core_init(dwc);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_otg_reset(dotg);
}
return 0;
@@ -253,7 +267,6 @@
{
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
- struct dwc3 *dwc = dotg->dwc;
if (!otg->gadget)
return -EINVAL;
@@ -262,20 +275,11 @@
dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
__func__, otg->gadget->name);
- /*
- * Hardware reset is required to support below scenarios:
- * 1. Host <-> peripheral switching
- * 2. Once an endpoint is configured in DBM (BAM) mode, it
- * can be unconfigured only after RESET
- */
+ /* Core reset is not required during start peripheral. Only
+ * DBM reset is required, hence perform only DBM reset here */
if (ext_xceiv && ext_xceiv->otg_capability &&
ext_xceiv->ext_block_reset)
- ext_xceiv->ext_block_reset();
-
- /* re-init core and OTG registers as block reset clears these */
- dwc3_post_host_reset_core_init(dwc);
- if (ext_xceiv && !ext_xceiv->otg_capability)
- dwc3_otg_reset(dotg);
+ ext_xceiv->ext_block_reset(false);
dwc3_otg_set_peripheral_regs(dotg);
usb_gadget_vbus_connect(otg->gadget);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index d3b1b4a..c2fab53 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -109,7 +109,7 @@
void (*notify_ext_events)(struct usb_otg *otg,
enum dwc3_ext_events ext_event);
/* for block reset USB core */
- void (*ext_block_reset)(void);
+ void (*ext_block_reset)(bool core_reset);
};
/* for external transceiver driver */
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index 6518095..cece500 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -410,7 +410,6 @@
clear_eps(f);
clear_desc(c->cdev->gadget, f);
- msm_dwc3_restart_usb_session();
}
static void qdss_eps_disable(struct usb_function *f)
@@ -467,13 +466,13 @@
qdss->usb_connected = 0;
spin_unlock_irqrestore(&qdss->lock, flags);
+ /*cancell all active xfers*/
+ qdss_eps_disable(f);
+
status = uninit_data(qdss->data);
if (status)
pr_err("%s: uninit_data error\n", __func__);
- /*cancell all active xfers*/
- qdss_eps_disable(f);
-
schedule_work(&qdss->disconnect_w);
}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ca4b01a..9879122 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -2106,7 +2106,9 @@
}
if (mehci->async_irq) {
- disable_irq_wake(mehci->async_irq);
+ /* Async IRQ is used only in absence of dedicated wakeup irq */
+ if (!mehci->wakeup_irq)
+ disable_irq_wake(mehci->async_irq);
free_irq(mehci->async_irq, mehci);
}
/*
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 66363eb..521ace0 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -117,6 +117,8 @@
return -ENOMEM;
}
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index faa5625..6727996 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1057,6 +1057,8 @@
return -ENOMEM;
}
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
diff --git a/drivers/usb/host/ehci-msm72k.c b/drivers/usb/host/ehci-msm72k.c
index 76cd977..bab330c 100644
--- a/drivers/usb/host/ehci-msm72k.c
+++ b/drivers/usb/host/ehci-msm72k.c
@@ -681,6 +681,8 @@
if (!hcd)
return -ENOMEM;
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/hbm.c b/drivers/usb/host/hbm.c
index d48a631..1a0c0aa 100644
--- a/drivers/usb/host/hbm.c
+++ b/drivers/usb/host/hbm.c
@@ -39,6 +39,7 @@
#define PIPE_PRODUCER 1
#define MAX_PIPE_NUM 16
#define HBM_QH_MAP_PIPE 0xffffffc0
+#define QTD_CERR_MASK 0xfffff3ff
struct hbm_msm {
u32 *base;
@@ -257,6 +258,7 @@
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct list_head qtd_list;
+ struct ehci_qtd *qtd;
INIT_LIST_HEAD(&qtd_list);
@@ -272,5 +274,11 @@
if (!qh_urb_transaction(ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
+
+ /* set err counter in qTD token to zero */
+ qtd = list_entry(qtd_list.next, struct ehci_qtd, qtd_list);
+ if (qtd != NULL)
+ qtd->hw_token &= QTD_CERR_MASK;
+
return hbm_submit_async(ehci, urb, &qtd_list, mem_flags);
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 7760d28..5750e0d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -3651,7 +3651,7 @@
cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
- ret = scm_call(SCM_SVC_CP, MSM_OTG_CMD_ID, &cmd_buf,
+ ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
sizeof(cmd_buf), NULL, 0);
if (ret)
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 77eb9c2..63a842d 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1609,7 +1609,6 @@
outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */
} else if (term == MDP_OVERLAY0_TERM) {
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_lut_enable();
outpdw(MDP_BASE + 0x0004, 0);
} else if (term == MDP_OVERLAY1_TERM) {
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 8515782..e850321 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -71,7 +71,7 @@
}
}
if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
- bus_ab_quota = bus_ab_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
+ bus_ab_quota = bus_ib_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 57bf9f2..258034b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3502,17 +3502,17 @@
static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
struct mdp_buf_sync *buf_sync)
{
- int i, fence_cnt = 0, ret;
+ int i, fence_cnt = 0, ret = 0;
int acq_fen_fd[MDP_MAX_FENCE_FD];
struct sync_fence *fence;
- if ((buf_sync->acq_fen_fd_cnt == 0) ||
- (buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+ if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
(mfd->timeline == NULL))
return -EINVAL;
- ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
- buf_sync->acq_fen_fd_cnt * sizeof(int));
+ if (buf_sync->acq_fen_fd_cnt)
+ ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
+ buf_sync->acq_fen_fd_cnt * sizeof(int));
if (ret) {
pr_err("%s:copy_from_user failed", __func__);
return ret;
@@ -3531,6 +3531,10 @@
fence_cnt = i;
if (ret)
goto buf_sync_err_1;
+ mfd->acq_fen_cnt = fence_cnt;
+ if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+ msm_fb_wait_for_fence(mfd);
+
mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
mfd->timeline_value + 2);
if (mfd->cur_rel_sync_pt == NULL) {
@@ -3557,7 +3561,6 @@
pr_err("%s:copy_to_user failed", __func__);
goto buf_sync_err_2;
}
- mfd->acq_fen_cnt = buf_sync->acq_fen_fd_cnt;
mutex_unlock(&mfd->sync_mutex);
return ret;
buf_sync_err_2:
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 281c72a..6484a3f 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -25,12 +25,12 @@
* struct devfreq_dev_status - Data given from devfreq user device to
* governors. Represents the performance
* statistics.
- * @total_time The total time represented by this instance of
+ * @total_time: The total time represented by this instance of
* devfreq_dev_status
- * @busy_time The time that the device was working among the
+ * @busy_time: The time that the device was working among the
* total_time.
- * @current_frequency The operating frequency.
- * @private_data An entry not specified by the devfreq framework.
+ * @current_frequency: The operating frequency.
+ * @private_data: An entry not specified by the devfreq framework.
* A device and a specific governor may have their
* own protocol with private_data. However, because
* this is governor-specific, a governor using this
@@ -54,23 +54,27 @@
/**
* struct devfreq_dev_profile - Devfreq's user device profile
- * @initial_freq The operating frequency when devfreq_add_device() is
+ * @initial_freq: The operating frequency when devfreq_add_device() is
* called.
- * @polling_ms The polling interval in ms. 0 disables polling.
- * @target The device should set its operating frequency at
+ * @polling_ms: The polling interval in ms. 0 disables polling.
+ * @target: The device should set its operating frequency at
* freq or lowest-upper-than-freq value. If freq is
* higher than any operable frequency, set maximum.
* Before returning, target function should set
* freq at the current frequency.
* The "flags" parameter's possible values are
* explained above with "DEVFREQ_FLAG_*" macros.
- * @get_dev_status The device should provide the current performance
+ * @get_dev_status: The device should provide the current performance
* status to devfreq, which is used by governors.
- * @exit An optional callback that is called when devfreq
+ * @get_cur_freq: The device should provide the current frequency
+ * at which it is operating.
+ * @exit: An optional callback that is called when devfreq
* is removing the devfreq object due to error or
* from devfreq_remove_device() call. If the user
* has registered devfreq->nb at a notifier-head,
* this is the time to unregister it.
+ * @freq_table: Optional list of frequencies to support statistics.
+ * @max_state: The size of freq_table.
*/
struct devfreq_dev_profile {
unsigned long initial_freq;
@@ -79,63 +83,62 @@
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
int (*get_dev_status)(struct device *dev,
struct devfreq_dev_status *stat);
+ int (*get_cur_freq)(struct device *dev, unsigned long *freq);
void (*exit)(struct device *dev);
+
+ unsigned int *freq_table;
+ unsigned int max_state;
};
/**
* struct devfreq_governor - Devfreq policy governor
- * @name Governor's name
- * @get_target_freq Returns desired operating frequency for the device.
+ * @node: list node - contains registered devfreq governors
+ * @name: Governor's name
+ * @get_target_freq: Returns desired operating frequency for the device.
* Basically, get_target_freq will run
* devfreq_dev_profile.get_dev_status() to get the
* status of the device (load = busy_time / total_time).
* If no_central_polling is set, this callback is called
* only with update_devfreq() notified by OPP.
- * @init Called when the devfreq is being attached to a device
- * @exit Called when the devfreq is being removed from a
- * device. Governor should stop any internal routines
- * before return because related data may be
- * freed after exit().
- * @no_central_polling Do not use devfreq's central polling mechanism.
- * When this is set, devfreq will not call
- * get_target_freq with devfreq_monitor(). However,
- * devfreq will call get_target_freq with
- * devfreq_update() notified by OPP framework.
+ * @event_handler: Callback for devfreq core framework to notify events
+ * to governors. Events include per device governor
+ * init and exit, opp changes out of devfreq, suspend
+ * and resume of per device devfreq during device idle.
*
* Note that the callbacks are called with devfreq->lock locked by devfreq.
*/
struct devfreq_governor {
+ struct list_head node;
+
const char name[DEVFREQ_NAME_LEN];
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
- int (*init)(struct devfreq *this);
- void (*exit)(struct devfreq *this);
- const bool no_central_polling;
+ int (*event_handler)(struct devfreq *devfreq,
+ unsigned int event, void *data);
};
/**
* struct devfreq - Device devfreq structure
- * @node list node - contains the devices with devfreq that have been
+ * @node: list node - contains the devices with devfreq that have been
* registered.
- * @lock a mutex to protect accessing devfreq.
- * @dev device registered by devfreq class. dev.parent is the device
+ * @lock: a mutex to protect accessing devfreq.
+ * @dev: device registered by devfreq class. dev.parent is the device
* using devfreq.
- * @profile device-specific devfreq profile
- * @governor method how to choose frequency based on the usage.
- * @nb notifier block used to notify devfreq object that it should
+ * @profile: device-specific devfreq profile
+ * @governor: method how to choose frequency based on the usage.
+ * @nb: notifier block used to notify devfreq object that it should
* reevaluate operable frequencies. Devfreq users may use
* devfreq.nb to the corresponding register notifier call chain.
- * @polling_jiffies interval in jiffies.
- * @previous_freq previously configured frequency value.
- * @next_polling the number of remaining jiffies to poll with
- * "devfreq_monitor" executions to reevaluate
- * frequency/voltage of the device. Set by
- * profile's polling_ms interval.
- * @data Private data of the governor. The devfreq framework does not
+ * @work: delayed work for load monitoring.
+ * @previous_freq: previously configured frequency value.
+ * @data: Private data of the governor. The devfreq framework does not
* touch this.
- * @being_removed a flag to mark that this object is being removed in
- * order to prevent trying to remove the object multiple times.
- * @min_freq Limit minimum frequency requested by user (0: none)
- * @max_freq Limit maximum frequency requested by user (0: none)
+ * @min_freq: Limit minimum frequency requested by user (0: none)
+ * @max_freq: Limit maximum frequency requested by user (0: none)
+ * @stop_polling: devfreq polling status of a device.
+ * @total_trans: Number of devfreq transitions
+ * @trans_table: Statistics of devfreq transitions
+ * @time_in_state: Statistics of devfreq states
+ * @last_stat_updated: The last time stat updated
*
* This structure stores the devfreq information for a give device.
*
@@ -153,17 +156,21 @@
struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor;
struct notifier_block nb;
+ struct delayed_work work;
- unsigned long polling_jiffies;
unsigned long previous_freq;
- unsigned int next_polling;
void *data; /* private data for governors */
- bool being_removed;
-
unsigned long min_freq;
unsigned long max_freq;
+ bool stop_polling;
+
+ /* information for device freqeuncy transition */
+ unsigned int total_trans;
+ unsigned int *trans_table;
+ unsigned long *time_in_state;
+ unsigned long last_stat_updated;
};
#if defined(CONFIG_PM_DEVFREQ)
@@ -172,6 +179,8 @@
const struct devfreq_governor *governor,
void *data);
extern int devfreq_remove_device(struct devfreq *devfreq);
+extern int devfreq_suspend_device(struct devfreq *devfreq);
+extern int devfreq_resume_device(struct devfreq *devfreq);
/* Helper functions for devfreq user device driver with OPP. */
extern struct opp *devfreq_recommended_opp(struct device *dev,
@@ -195,9 +204,9 @@
/**
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
* and devfreq_add_device
- * @ upthreshold If the load is over this value, the frequency jumps.
+ * @upthreshold: If the load is over this value, the frequency jumps.
* Specify 0 to use the default. Valid value = 0 to 100.
- * @ downdifferential If the load is under upthreshold - downdifferential,
+ * @downdifferential: If the load is under upthreshold - downdifferential,
* the governor may consider slowing the frequency down.
* Specify 0 to use the default. Valid value = 0 to 100.
* downdifferential < upthreshold must hold.
@@ -225,6 +234,16 @@
return 0;
}
+static int devfreq_suspend_device(struct devfreq *devfreq)
+{
+ return 0;
+}
+
+static int devfreq_resume_device(struct devfreq *devfreq)
+{
+ return 0;
+}
+
static struct opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq, u32 flags)
{
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 2cea256..6e50578 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -189,28 +189,28 @@
/* Events associated with each demux filter */
enum dmx_event {
/* New PES packet is ready to be consumed */
- DMX_EVENT_NEW_PES,
+ DMX_EVENT_NEW_PES = 0x00000001,
/* New section is ready to be consumed */
- DMX_EVENT_NEW_SECTION,
+ DMX_EVENT_NEW_SECTION = 0x00000002,
/* New recording chunk is ready to be consumed */
- DMX_EVENT_NEW_REC_CHUNK,
+ DMX_EVENT_NEW_REC_CHUNK = 0x00000004,
/* New PCR value is ready */
- DMX_EVENT_NEW_PCR,
+ DMX_EVENT_NEW_PCR = 0x00000008,
/* Overflow */
- DMX_EVENT_BUFFER_OVERFLOW,
+ DMX_EVENT_BUFFER_OVERFLOW = 0x00000010,
/* Section was dropped due to CRC error */
- DMX_EVENT_SECTION_CRC_ERROR,
+ DMX_EVENT_SECTION_CRC_ERROR = 0x00000020,
/* End-of-stream, no more data from this filter */
- DMX_EVENT_EOS,
+ DMX_EVENT_EOS = 0x00000040,
/* New Elementary Stream data is ready */
- DMX_EVENT_NEW_ES_DATA
+ DMX_EVENT_NEW_ES_DATA = 0x00000080
};
/* Flags passed in filter events */
@@ -552,7 +552,6 @@
int handle;
};
-
struct dmx_decoder_buffers {
/*
* Specify if linear buffer support is requested. If set, buffers_num
@@ -587,6 +586,35 @@
__u32 key_ladder_id;
};
+struct dmx_events_mask {
+ /*
+ * Bitmask of events to be disabled (dmx_event).
+ * Disabled events will not be notified to the user.
+ * By default all events are enabled except for
+ * DMX_EVENT_NEW_ES_DATA.
+ * Overflow event can't be disabled.
+ */
+ __u32 disable_mask;
+
+ /*
+ * Bitmask of events that will not wake-up the user
+ * when user calls poll with POLLPRI flag.
+ * Events that are used as wake-up source should not be
+ * disabled in disable_mask or they would not be used
+ * as a wake-up source.
+ * By default all enabled events are set as wake-up events.
+ * Overflow event can't be disabled as a wake-up source.
+ */
+ __u32 no_wakeup_mask;
+
+ /*
+ * Number of ready wake-up events which will trigger
+ * a wake-up when user calls poll with POLLPRI flag.
+ * Default is set to 1.
+ */
+ __u32 wakeup_threshold;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -611,6 +639,8 @@
#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)
+#define DMX_SET_EVENTS_MASK _IOW('o', 66, struct dmx_events_mask)
+#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/opp.h b/include/linux/opp.h
index 2a4e5fa..214e0eb 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -48,6 +48,14 @@
struct srcu_notifier_head *opp_get_notifier(struct device *dev);
+#ifdef CONFIG_OF
+int of_init_opp_table(struct device *dev);
+#else
+static inline int of_init_opp_table(struct device *dev)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF */
#else
static inline unsigned long opp_get_voltage(struct opp *opp)
{
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index d4fb732..74b09cb 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1852,6 +1852,8 @@
};
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
(V4L2_CID_MPEG_MSM_VIDC_BASE+27)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+28)
/* 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_vidc.h b/include/media/msm_vidc.h
index 9b8a222..f632ad6 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -46,6 +46,7 @@
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
int msm_vidc_wait(void *instance);
int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
#endif
struct msm_vidc_interlace_payload {
unsigned int format;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index ae34bf5..d1e73a4 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -61,6 +61,7 @@
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
+ .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
.clock_base =
{
{
@@ -1619,8 +1620,6 @@
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
int i;
- raw_spin_lock_init(&cpu_base->lock);
-
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
cpu_base->clock_base[i].cpu_base = cpu_base;
timerqueue_init_head(&cpu_base->clock_base[i].active);
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 328e287..4dc6505 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -86,6 +86,7 @@
static struct mutex cdc_mclk_mutex;
static struct clk *codec_clk;
static int clk_users;
+static int vdd_spkr_gpio = -1;
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm)
@@ -149,6 +150,30 @@
return 0;
}
+static int msm8226_vdd_spkr_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (vdd_spkr_gpio >= 0) {
+ gpio_direction_output(vdd_spkr_gpio, 1);
+ pr_debug("%s: Enabled 5V external supply for speaker\n",
+ __func__);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (vdd_spkr_gpio >= 0) {
+ gpio_direction_output(vdd_spkr_gpio, 0);
+ pr_debug("%s: Disabled 5V external supply for speaker\n",
+ __func__);
+ }
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget msm8226_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
@@ -165,6 +190,9 @@
SND_SOC_DAPM_MIC("Digital Mic4", NULL),
SND_SOC_DAPM_MIC("Digital Mic5", NULL),
SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+
+ SND_SOC_DAPM_SUPPLY("EXT_VDD_SPKR", SND_SOC_NOPM, 0, 0,
+ msm8226_vdd_spkr_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const char *const slim0_rx_ch_text[] = {"One", "Two"};
@@ -1104,19 +1132,44 @@
goto err;
}
+ vdd_spkr_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-vdd-spkr-gpios", 0);
+ if (vdd_spkr_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-vdd-spkr-gpios",
+ pdev->dev.of_node->full_name, vdd_spkr_gpio);
+ } else {
+ ret = gpio_request(vdd_spkr_gpio, "TAPAN_CODEC_VDD_SPKR");
+ if (ret) {
+ /* GPIO to enable EXT VDD exists, but failed request */
+ dev_err(card->dev,
+ "%s: Failed to request tapan vdd spkr gpio %d\n",
+ __func__, vdd_spkr_gpio);
+ goto err;
+ }
+ }
+
ret = msm8226_prepare_codec_mclk(card);
if (ret)
- goto err;
+ goto err_vdd_spkr;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
- goto err;
+ goto err_vdd_spkr;
}
mutex_init(&cdc_mclk_mutex);
return 0;
+
+err_vdd_spkr:
+ if (vdd_spkr_gpio >= 0) {
+ gpio_free(vdd_spkr_gpio);
+ vdd_spkr_gpio = -1;
+ }
+
err:
if (pdata->mclk_gpio > 0) {
dev_dbg(&pdev->dev, "%s free gpio %d\n",
@@ -1134,6 +1187,8 @@
struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
gpio_free(pdata->mclk_gpio);
+ gpio_free(vdd_spkr_gpio);
+ vdd_spkr_gpio = -1;
snd_soc_unregister_card(card);
return 0;