Merge "msm_fb: Change refx100 value for NT35510 panel in command mode" into msm-3.4
diff --git a/Documentation/ABI/testing/sysfs-bus-msm_subsys b/Documentation/ABI/testing/sysfs-bus-msm_subsys
new file mode 100644
index 0000000..fcfb1d4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-msm_subsys
@@ -0,0 +1,18 @@
+What: /sys/bus/msm_subsys/devices/.../name
+Date: July 2012
+Contact: Stephen Boyd <sboyd@codeaurora.org>
+Description:
+ Shows the name of the subsystem.
+
+What: /sys/bus/msm_subsys/devices/.../state
+Date: July 2012
+Contact: Stephen Boyd <sboyd@codeaurora.org>
+Description:
+ Shows the state state of a subsystem. Current states
+ supported are:
+
+ OFFLINE - subsystem is offline
+ ONLINE - subsystem is online
+
+ This file supports poll(3) to detect when a subsystem changes
+ state. Use POLLPRI to detect state changes.
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
new file mode 100644
index 0000000..1ec3081
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -0,0 +1,34 @@
+MSM Bus Scaling Driver
+
+The msm bus scaling driver provides the ability to configure
+bus performance parameters across the entire chip-set.
+Various clients use MSM scaling APIs to request bandwidth
+between multiple master-slave pairs. The bus driver then finds
+the optimal path between the master and the slave, and aggregates
+the bandwidth and clock requests for all master-slave pairs on
+that path, and programs hardware accordingly.
+
+The device-tree data required for bus-scaling can be embedded within
+the clients' device nodes. The clients can register with the bus driver
+using the following properties:
+
+- qcom,msm_bus,name: String representing the client-name
+- qcom,msm_bus,num_cases: Total number of usecases
+- qcom,msm_bus,active_only: Context flag for requests in active or
+ dual (active & sleep) contex
+- qcom,msm_bus,num_paths: Total number of master-slave pairs
+- qcom,msm_bus,vectors: Arrays of unsigned integers representing:
+ master-id, slave-id, arbitrated bandwidth,
+ instantaneous bandwidth
+
+Example:
+
+ qcom,msm_bus,name = "client-name";
+ qcom,msm_bus,num_cases = <3>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <2>;
+ qcom,msm_bus,vectors =
+ <22 512 0 0>, <26 512 0 0>,
+ <22 512 320000 320000000>, <26 512 3200000 320000000>,
+ <22 512 160000 160000000>, <26 512 1600000 160000000>;
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 75916e5..6b03fab 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -1,5 +1,6 @@
* Qualcomm MSM CCI
+[First level nodes]
Required properties:
- cell-index: cci hardware core index
- compatible :
@@ -11,6 +12,102 @@
- interrupt-names : should specify relevant names to each interrupts
property defined.
+[Second level nodes]
+* Qualcomm MSM Sensor
+
+MSM sensor node contains properties of camera sensor
+
+Required properties:
+- compatible : should be "qcom" followed by sensor name
+ - "qcom,s5k3l1yx"
+- reg : should contain i2c slave address of the camera sensor and
+ length of data field which is 0x0
+- qcom,csi-if : should contain number of csid cores required at the receiver
+ side
+ - 1 for 2D sensor
+ - 2 for 3D sensor
+- qcom,csid-core : should contain csid core instance that will used to receive
+ sensor data
+ - 0, 1, 2, 3
+- qcom,is-vpe : should be enabled if VPE module is required for post processing
+ of this sensor
+ - 1 if required, 0 otherwise
+- qcom,sensor-name : should contain unique sensor name to differentiate from
+ other sensor
+ - "s5k3l1yx"
+- cam_vdig-supply : should contain regulator from which digital voltage is
+ supplied
+- cam_vana-supply : should contain regulator from which analog voltage is
+ supplied
+- cam_vio-supply : should contain regulator from which IO voltage is supplied
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+ sensor
+ - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf"
+- qcom,cam-vreg-type : should contain regulator type for regulators mentioned in
+ qcom,cam-vreg-name property (in the same order)
+ - 0 for LDO and 1 for LVS
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level for
+ regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level for
+ regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators
+ mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,camera-type : should contain sensor type
+ - 0 -> back camera 2D
+ - 1 -> front camera 2D
+ - 2 -> back camera 3D
+ - 3 -> back camera int 3D
+- qcom,sensor-type : should contain format of data that sensor streams
+ - 0 -> bayer format
+ - 1 -> yuv format
+
+Optional properties:
+- qcom,flash-type : should contain flash type if flash is supported for this
+ sensor
+ - 0 if flash is not supported, 1 if flash is supported
+- qcom,mount-angle : should contain the physical mount angle of the sensor on
+ the target
+ - 0, 90, 180, 360
+- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is
+ available
+ - 1 if gpio mux is not available, 0 otherwise
+- cam_vaf-supply : should contain regulator from which AF voltage is supplied
+- gpios : should contain phandle to gpio controller node and array of
+ #gpio-cells specifying specific gpio (controller specific)
+- qcom,gpio-common-tbl-num : should contain index to gpios shared between
+ different sensors
+- qcom,gpio-common-tbl-flags : should contain direction of gpios present in
+ qcom,gpio-common-tbl-num property (in the same order)
+- qcom,gpio-common-tbl-label : should contain name of gpios present in
+ qcom,gpio-common-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+ qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+ qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-num : should contain index of gpios that need to be
+ configured by msm
+- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios
+ present in qcom,gpio-set-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring
+ gpios as specified in gpio_set_tbl_flags property (in the same order)
+- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY
+ lanes to CSID lanes
+ - 0x4320
+- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to
+ be enabled
+- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should
+ receive data
+- qcom,actuator-cam-name : should contain actuator cam name associated with
+ this sensor
+ - If actuator does not exist, this property should not be initialized
+ - If actuator exist, this field should indicate the index of actuator to
+ be used
+- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled
+ for actuator
+- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm
+ gpio
+
Example:
qcom,cci@0xfda0c000 {
@@ -20,4 +117,43 @@
reg-names = "cci";
interrupts = <0 50 0>;
interrupt-names = "cci";
+ qcom,s5k3l1yx@6e {
+ compatible = "qcom,s5k3l1yx";
+ reg = <0x6e 0x0>;
+ qcom,csi-if = <1>;
+ qcom,csid-core = <0>;
+ qcom,is-vpe = <1>;
+ qcom,flash-type = <0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "s5k3l1yx";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", "cam_vaf";
+ qcom,cam-vreg-type = <0 0 1 0>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+ qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 19 0>,
+ <&msmgpio 20 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-common-tbl-num = <0 1 2>;
+ qcom,gpio-common-tbl-flags = <1 1 1>;
+ qcom,gpio-common-tbl-label = "CAMIF_MCLK", "CAMIF_I2C_DATA",
+ "CAMIF_I2C_CLK";
+ qcom,gpio-req-tbl-num = <3>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <3 3>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,csi-phy-sel = <0>;
+ qcom,camera-type = <0>;
+ qcom,sensor-type = <0>;
+ };
};
diff --git a/Documentation/devicetree/bindings/media/video/msm-sensor.txt b/Documentation/devicetree/bindings/media/video/msm-sensor.txt
deleted file mode 100644
index e242d51..0000000
--- a/Documentation/devicetree/bindings/media/video/msm-sensor.txt
+++ /dev/null
@@ -1,137 +0,0 @@
-* Qualcomm MSM Sensor
-
-MSM sensor node contains properties of camera sensor
-
-Required properties:
-- compatible : should be "qcom" followed by sensor name
- - "qcom,s5k3l1yx"
-- reg : should contain i2c slave address of the camera sensor and
- length of data field which is 0x0
-- qcom,csi-if : should contain number of csid cores required at the receiver
- side
- - 1 for 2D sensor
- - 2 for 3D sensor
-- qcom,csid-core : should contain csid core instance that will used to receive
- sensor data
- - 0, 1, 2, 3
-- qcom,is-vpe : should be enabled if VPE module is required for post processing
- of this sensor
- - 1 if required, 0 otherwise
-- qcom,sensor-name : should contain unique sensor name to differentiate from
- other sensor
- - "s5k3l1yx"
-- cam_vdig-supply : should contain regulator from which digital voltage is
- supplied
-- cam_vana-supply : should contain regulator from which analog voltage is
- supplied
-- cam_vio-supply : should contain regulator from which IO voltage is supplied
-- qcom,cam-vreg-name : should contain names of all regulators needed by this
- sensor
- - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf"
-- qcom,cam-vreg-type : should contain regulator type for regulators mentioned in
- qcom,cam-vreg-name property (in the same order)
- - 0 for LDO and 1 for LVS
-- qcom,cam-vreg-min-voltage : should contain minimum voltage level for
- regulators mentioned in qcom,cam-vreg-name property (in the same order)
-- qcom,cam-vreg-max-voltage : should contain maximum voltage level for
- regulators mentioned in qcom,cam-vreg-name property (in the same order)
-- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators
- mentioned in qcom,cam-vreg-name property (in the same order)
-- qcom,camera-type : should contain sensor type
- - 0 -> back camera 2D
- - 1 -> front camera 2D
- - 2 -> back camera 3D
- - 3 -> back camera int 3D
-- qcom,sensor-type : should contain format of data that sensor streams
- - 0 -> bayer format
- - 1 -> yuv format
-
-Optional properties:
-- qcom,flash-type : should contain flash type if flash is supported for this
- sensor
- - 0 if flash is not supported, 1 if flash is supported
-- qcom,mount-angle : should contain the physical mount angle of the sensor on
- the target
- - 0, 90, 180, 360
-- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is
- available
- - 1 if gpio mux is not available, 0 otherwise
-- cam_vaf-supply : should contain regulator from which AF voltage is supplied
-- gpios : should contain phandle to gpio controller node and array of
- #gpio-cells specifying specific gpio (controller specific)
-- qcom,gpio-common-tbl-num : should contain index to gpios shared between
- different sensors
-- qcom,gpio-common-tbl-flags : should contain direction of gpios present in
- qcom,gpio-common-tbl-num property (in the same order)
-- qcom,gpio-common-tbl-label : should contain name of gpios present in
- qcom,gpio-common-tbl-num property (in the same order)
-- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
-- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
- qcom,gpio-req-tbl-num property (in the same order)
-- qcom,gpio-req-tbl-label : should contain name of gpios present in
- qcom,gpio-req-tbl-num property (in the same order)
-- qcom,gpio-set-tbl-num : should contain index of gpios that need to be
- configured by msm
-- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios
- present in qcom,gpio-set-tbl-num property (in the same order)
-- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring
- gpios as specified in gpio_set_tbl_flags property (in the same order)
-- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY
- lanes to CSID lanes
- - 0x4320
-- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to
- be enabled
-- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should
- receive data
-- qcom,actuator-cam-name : should contain actuator cam name associated with
- this sensor
- - If actuator does not exist, this property should not be initialized
- - If actuator exist, this field should indicate the index of actuator to
- be used
-- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled
- for actuator
-- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm
- gpio
-
-Example:
-
-qcom,s5k3l1yx@6e {
- compatible = "qcom,s5k3l1yx";
- reg = <0x6e 0x0>;
- qcom,csi-if = <1>;
- qcom,csid-core = <0>;
- qcom,is-vpe = <1>;
- qcom,flash-type = <0>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "s5k3l1yx";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", "cam_vaf";
- qcom,cam-vreg-type = <0 0 1 0>;
- qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
- qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 19 0>,
- <&msmgpio 20 0>,
- <&msmgpio 90 0>;
- qcom,gpio-common-tbl-num = <0 1 2>;
- qcom,gpio-common-tbl-flags = <1 1 1>;
- qcom,gpio-common-tbl-label = "CAMIF_MCLK", "CAMIF_I2C_DATA",
- "CAMIF_I2C_CLK";
- qcom,gpio-req-tbl-num = <3>;
- qcom,gpio-req-tbl-flags = <0>;
- qcom,gpio-req-tbl-label = "CAM_RESET1";
- qcom,gpio-set-tbl-num = <3 3>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 4000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,csi-phy-sel = <0>;
- qcom,camera-type = <0>;
- qcom,sensor-type = <0>;
-};
-
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
new file mode 100644
index 0000000..e394b56
--- /dev/null
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -0,0 +1,45 @@
+* Qualcomm WCNSS Platform Driver
+
+WCNSS driver is the platform driver. It is used for performing the cold
+boot-up of the wireless device. It is responsible for adjusting
+the necessary I/O rails and enabling appropriate gpios for wireless
+connectivity subsystem.
+
+Required properties:
+- compatible: "wcnss_wlan"
+- reg: offset and length of the register set for the device. The pair
+ corresponds to PRONTO.
+- interupts: Pronto to Apps interrupts for tx done and rx pending.
+- qcom,pronto-vddmx-supply: regulator to supply pronto pll.
+- qcom,pronto-vddcx-supply: regulator to supply WLAN/BT/FM digital module.
+- qcom,pronto-vddpx-supply: regulator to supply WLAN DAC.
+- qcom,iris-vddxo-supply : regulator to supply RF XO.
+- qcom,iris-vddrfa-supply : regulator to supply RFA digital.
+- qcom,iris-vddpa-supply : regulator to supply RF PA.
+- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
+- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
+- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+
+Example:
+
+ qcom,wcnss-wlan@fb000000 {
+ compatible = "qcom,wcnss_wlan";
+ reg = <0xfb000000 0x280000>;
+ reg-names = "wcnss_mmio";
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8841_s1>;
+ qcom,pronto-vddcx-supply = <&pm8841_s2>;
+ qcom,pronto-vddpx-supply = <&pm8941_s3>;
+ qcom,iris-vddxo-supply = <&pm8941_l6>;
+ qcom,iris-vddrfa-supply = <&pm8941_l11>;
+ qcom,iris-vddpa-supply = <&pm8941_l19>;
+ qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+ gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
+ <&msmgpio 39 0>, <&msmgpio 40 0>;
+ qcom,has_48mhz_xo;
+ qcom,has_pronto_hw;
+ };
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
old mode 100644
new mode 100755
index 6347b51..751a823
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -378,7 +378,18 @@
label = "usb_in";
qcom,channel-num = <0>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <20>;
+ qcom,pre-div-channel-scaling = <4>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@1 {
+ label = "dc_in";
+ qcom,channel-num = <1>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <4>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -389,6 +400,28 @@
label = "vchg_sns";
qcom,channel-num = <2>;
qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <3>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@3 {
+ label = "spare1";
+ qcom,channel-num = <3>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <6>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4 {
+ label = "spare2";
+ qcom,channel-num = <4>;
+ qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <6>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
@@ -400,7 +433,7 @@
label = "vcoin";
qcom,channel-num = <5>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -411,7 +444,7 @@
label = "vbat_sns";
qcom,channel-num = <6>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -422,18 +455,29 @@
label = "vph_pwr";
qcom,channel-num = <7>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
+ chan@8 {
+ label = "die_temp";
+ qcom,channel-num = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
chan@9 {
label = "ref_625mv";
qcom,channel-num = <9>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
+ qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -441,15 +485,48 @@
};
chan@10 {
- label = "ref_1125v";
+ label = "ref_1250v";
qcom,channel-num = <10>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <1>;
+ qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
+
+ chan@48 {
+ label = "batt_therm";
+ qcom,channel-num = <48>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@49 {
+ label = "batt_id";
+ qcom,channel-num = <49>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@50 {
+ label = "xo_therm1";
+ qcom,channel-num = <49>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
};
iadc@3600 {
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index fd35103..c92188a 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -254,7 +254,7 @@
qcom,csi-lane-assign = <0x4320>;
qcom,csi-lane-mask = <0x7>;
qcom,csi-phy-sel = <1>;
- qcom,camera-type = <0>;
+ qcom,camera-type = <1>;
qcom,sensor-type = <0>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index e764e01..a9ed9ea 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -18,7 +18,7 @@
/ {
model = "Qualcomm MSM 8974 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974";
- qcom,msm-id = <126 1 0>, <126 8 0>;
+ qcom,msm-id = <126 1 0>;
serial@f991e000 {
status = "ok";
@@ -29,6 +29,117 @@
status = "ok";
};
};
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 760 1424>;
+ atmel,display-coords = <0 0 720 1280>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x82>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 15 00 02 10 08 0C 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 32 03
+ /* Object 8, Instance = 0 */
+ 0F 00 0A 0A 00 00 0A 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 18 0E 00 70 32 02 01
+ 00 03 01 01 05 0A 0A 0A 90 05
+ F8 02 00 00 0F 0F 00 00 48 2D
+ 07 0C 00 00 00 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 03 00 00 01
+ /* Object 47, Instance = 0 */
+ 08 0A 28 0A 02 0A 00 8C 00 20
+ 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 03 00 01 18 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 61, Instance = 1 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 7F 03 00 16 00 00 00 00 00 00
+ 04 08 10 18 05 00 0A 05 05 50
+ 14 19 34 1A 64 00 00 04 40 00
+ 00 00 00 00 30 32 02 00 01 00
+ 05 00 00 00 00 00 00 00 00 00
+ 00 00 0C 00
+ ];
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
&sdcc2 {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
new file mode 100644
index 0000000..1af468a
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974 MTP";
+ compatible = "qcom,msm8974-mtp", "qcom,msm8974";
+ qcom,msm-id = <126 8 0>;
+
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_toshiba_720p_video {
+ status = "ok";
+ };
+ };
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 760 1424>;
+ atmel,display-coords = <0 0 720 1280>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x82>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 15 00 02 10 08 0C 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 32 03
+ /* Object 8, Instance = 0 */
+ 0F 00 0A 0A 00 00 0A 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 18 0E 00 70 32 02 01
+ 00 03 01 01 05 0A 0A 0A 90 05
+ F8 02 00 00 0F 0F 00 00 48 2D
+ 07 0C 00 00 00 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 03 00 00 01
+ /* Object 47, Instance = 0 */
+ 08 0A 28 0A 02 0A 00 8C 00 20
+ 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 03 00 01 18 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 61, Instance = 1 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 7F 03 00 16 00 00 00 00 00 00
+ 04 08 10 18 05 00 0A 05 05 50
+ 14 19 34 1A 64 00 00 04 40 00
+ 00 00 00 00 30 32 02 00 01 00
+ 05 00 00 00 00 00 00 00 00 00
+ 00 00 0C 00
+ ];
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+};
+
+&sdcc2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index fcc5070..3a2c9f2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -541,84 +541,6 @@
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <24000000>;
-
- atmel_mxt_ts@4a {
- compatible = "atmel,mxt-ts";
- reg = <0x4a>;
- interrupt-parent = <&msmgpio>;
- interrupts = <61 0x2>;
- vdd_ana-supply = <&pm8941_l18>;
- vcc_i2c-supply = <&pm8941_lvs1>;
- atmel,reset-gpio = <&msmgpio 60 0x00>;
- atmel,irq-gpio = <&msmgpio 61 0x00>;
- atmel,panel-coords = <0 0 760 1424>;
- atmel,display-coords = <0 0 720 1280>;
- atmel,i2c-pull-up = <1>;
- atmel,cfg_1 {
- atmel,family-id = <0x82>;
- atmel,variant-id = <0x19>;
- atmel,version = <0x10>;
- atmel,build = <0xaa>;
- atmel,config = [
- /* Object 6, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 38, Instance = 0 */
- 15 00 02 10 08 0C 00 00
- /* Object 7, Instance = 0 */
- FF FF 32 03
- /* Object 8, Instance = 0 */
- 0F 00 0A 0A 00 00 0A 00 00 00
- /* Object 9, Instance = 0 */
- 83 00 00 18 0E 00 70 32 02 01
- 00 03 01 01 05 0A 0A 0A 90 05
- F8 02 00 00 0F 0F 00 00 48 2D
- 07 0C 00 00 00 00
- /* Object 15, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00
- /* Object 18, Instance = 0 */
- 00 00
- /* Object 19, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 23, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 25, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 40, Instance = 0 */
- 00 00 00 00 00
- /* Object 42, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- /* Object 46, Instance = 0 */
- 00 00 10 10 00 00 03 00 00 01
- /* Object 47, Instance = 0 */
- 08 0A 28 0A 02 0A 00 8C 00 20
- 00 00 00
- /* Object 55, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 56, Instance = 0 */
- 03 00 01 18 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00
- /* Object 57, Instance = 0 */
- 00 00 00
- /* Object 61, Instance = 0 */
- 00 00 00 00 00
- /* Object 61, Instance = 1 */
- 00 00 00 00 00
- /* Object 62, Instance = 0 */
- 7F 03 00 16 00 00 00 00 00 00
- 04 08 10 18 05 00 0A 05 05 50
- 14 19 34 1A 64 00 00 04 40 00
- 00 00 00 00 30 32 02 00 01 00
- 05 00 00 00 00 00 00 00 00 00
- 00 00 0C 00
- ];
- };
- };
};
qcom,acpuclk@f9000000 {
@@ -788,6 +710,26 @@
qcom,firmware-name = "wcnss";
};
+ qcom,wcnss-wlan@fb000000 {
+ compatible = "qcom,wcnss_wlan";
+ reg = <0xfb000000 0x280000>;
+ reg-names = "wcnss_mmio";
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8841_s1>;
+ qcom,pronto-vddcx-supply = <&pm8841_s2>;
+ qcom,pronto-vddpx-supply = <&pm8941_s3>;
+ qcom,iris-vddxo-supply = <&pm8941_l6>;
+ qcom,iris-vddrfa-supply = <&pm8941_l11>;
+ qcom,iris-vddpa-supply = <&pm8941_l19>;
+ qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+ gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
+ qcom,has_48mhz_xo;
+ qcom,has_pronto_hw;
+ };
+
qcom,ocmem@fdd00000 {
compatible = "qcom,msm-ocmem";
reg = <0xfdd00000 0x2000>,
@@ -995,37 +937,6 @@
qcom,freq-step = <2>;
};
- gpio_keys {
- compatible = "gpio-keys";
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&pm8941_gpios 3 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_focus {
- label = "camera_focus";
- gpios = <&pm8941_gpios 4 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&pm8941_gpios 5 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
qcom,bam_dmux@fc834000 {
compatible = "qcom,bam_dmux";
reg = <0xfc834000 0x7000>;
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 82d317d..9582e78 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -305,14 +305,14 @@
qcom,mpm@fc4281d0 {
compatible = "qcom,mpm-v2";
reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
- <0xfa006000 0x1000>; /* MSM_APCS_GCC_BASE 4K */
+ <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
reg-names = "vmpm", "ipc";
interrupts = <0 171 1>;
- qcom,ipc-bit-offset = <0>;
+ qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <41 180>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 180>, /* usb2_hsic_async_wakeup_irq */
<53 104>, /* mdss_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 07233bb..7b7adca 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -97,4 +97,13 @@
spi-max-frequency = <5000000>;
};
};
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <1 2 0>, <1 1 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping = <0>;
+ };
};
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 0a99036..105572b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -54,7 +54,7 @@
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_DLOAD_MODE=y
@@ -186,6 +186,8 @@
CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_OV2720=y
+CONFIG_MSM_JPEG=y
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
@@ -194,6 +196,7 @@
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -306,3 +309,7 @@
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_CFG80211=m
+CONFIG_RFKILL=y
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 0d0103a..88d0872 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -113,7 +113,6 @@
struct mutex reserve_mutex;
u64 max_period;
struct platform_device *plat_device;
- u32 from_idle;
irqreturn_t (*handle_irq)(int irq_num, void *dev);
int (*request_pmu_irq)(int irq, irq_handler_t *irq_h);
void (*free_pmu_irq)(int irq);
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 23d310d..2455d1f 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -192,11 +192,17 @@
static void arch_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
+ unsigned long ctrl;
+
switch (mode) {
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
arch_timer_disable();
break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
+ ctrl |= ARCH_TIMER_CTRL_ENABLE;
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
default:
break;
}
@@ -208,11 +214,9 @@
unsigned long ctrl;
ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
- ctrl &= ~(ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK);
+ ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
arch_specific_timer->reg_write(ARCH_TIMER_REG_TVAL, evt);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
return 0;
}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index e97aef2..3f6a6d3 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -41,6 +41,7 @@
*/
#define ARMPMU_MAX_HWEVENTS 32
+static DEFINE_PER_CPU(u32, from_idle);
static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
@@ -602,7 +603,7 @@
int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
int idx;
- if (armpmu->from_idle) {
+ if (__get_cpu_var(from_idle)) {
for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
struct perf_event *event = hw_events->events[idx];
@@ -613,9 +614,12 @@
}
/* Reset bit so we don't needlessly re-enable counters.*/
- armpmu->from_idle = 0;
+ __get_cpu_var(from_idle) = 0;
}
+ /* So we don't start the PMU before enabling counters after idle. */
+ barrier();
+
if (enabled)
armpmu->start();
}
@@ -731,7 +735,6 @@
* UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
* junk values out of them.
*/
-
static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
unsigned long action, void *hcpu)
{
@@ -805,7 +808,7 @@
* Flip this bit so armpmu_enable knows it needs
* to re-enable active counters.
*/
- cpu_pmu->from_idle = 1;
+ __get_cpu_var(from_idle) = 1;
cpu_pmu->reset(NULL);
perf_pmu_enable(&cpu_pmu->pmu);
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6f0a7e7..e14eb5a 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2010,6 +2010,15 @@
gss hardware watchdog interrupt lines and plugs into the subsystem
restart and PIL drivers.
+config MSM_MODEM_SSR_8974
+ bool "MSM 8974 Modem restart driver"
+ depends on (ARCH_MSM8974)
+ help
+ This option enables the modem subsystem restart driver for the MSM8974.
+ It monitors the modem SMSM status bits and the modem watchdog line and
+ restarts the modem or the 8974 when the modem encounters a fatal error,
+ depending on the restart level selected in the subsystem restart driver.
+
config SCORPION_Uni_45nm_BUG
bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 524ec89..29bef02 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -210,6 +210,7 @@
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
+obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
new file mode 100644
index 0000000..0ded432
--- /dev/null
+++ b/arch/arm/mach-msm/adsp-8974.c
@@ -0,0 +1,295 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "ramdump.h"
+#include "sysmon.h"
+
+#define SCM_Q6_NMI_CMD 0x1
+#define MODULE_NAME "adsp_8974"
+#define MAX_BUF_SIZE 0x51
+
+/* Subsystem restart: QDSP6 data, functions */
+static void lpass_fatal_fn(struct work_struct *);
+static DECLARE_WORK(lpass_fatal_work, lpass_fatal_fn);
+
+struct lpass_ssr {
+ void *lpass_ramdump_dev;
+} lpass_ssr;
+
+static struct lpass_ssr lpass_ssr_8974;
+static int q6_crash_shutdown;
+
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__,
+ ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static void *ssr_notif_hdle;
+static struct notifier_block rnb = {
+ .notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__,
+ ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static void *ssr_modem_notif_hdle;
+static struct notifier_block mnb = {
+ .notifier_call = modem_notifier_cb,
+};
+
+static void lpass_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[MAX_BUF_SIZE];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
+ MODULE_NAME);
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("%s: subsystem failure reason: (unknown, init value found)",
+ MODULE_NAME);
+ return;
+ }
+
+ size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
+static void lpass_fatal_fn(struct work_struct *work)
+{
+ pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
+ __func__);
+ lpass_log_failure_reason();
+ panic(MODULE_NAME ": Resetting the SoC");
+}
+
+static void lpass_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (q6_crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_debug("%s: LPASS SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
+ __func__, new_state, old_state);
+ lpass_log_failure_reason();
+ panic(MODULE_NAME ": Resetting the SoC");
+ }
+}
+
+static void send_q6_nmi(void)
+{
+ /* Send NMI to QDSP6 via an SCM call. */
+ scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+ pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+static int lpass_shutdown(const struct subsys_desc *subsys)
+{
+ send_q6_nmi();
+
+ /* The write needs to go through before the q6 is shutdown. */
+ mb();
+
+ pil_force_shutdown("q6");
+ disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
+
+ return 0;
+}
+
+static int lpass_powerup(const struct subsys_desc *subsys)
+{
+ int ret;
+
+ if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
+ pr_debug("%s: Wait for ADSP power up!", __func__);
+ msleep(10000);
+ }
+
+ ret = pil_force_boot("q6");
+ enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
+ return ret;
+}
+/* RAM segments - address and size for 8974 */
+static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
+ 0x8da00000}, {0x28400000, 0x20000} };
+static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ pr_debug("%s: enable[%d]\n", __func__, enable);
+ if (enable)
+ return do_ramdump(lpass_ssr_8974.lpass_ramdump_dev,
+ q6_segments,
+ ARRAY_SIZE(q6_segments));
+ else
+ return 0;
+}
+
+static void lpass_crash_shutdown(const struct subsys_desc *subsys)
+{
+ q6_crash_shutdown = 1;
+ send_q6_nmi();
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+ int ret;
+
+ pr_debug("%s: rxed irq[0x%x]", __func__, irq);
+ disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
+ ret = schedule_work(&lpass_fatal_work);
+
+ return IRQ_HANDLED;
+}
+
+static struct subsys_device *lpass_8974_dev;
+
+static struct subsys_desc lpass_8974 = {
+ .name = "lpass",
+ .shutdown = lpass_shutdown,
+ .powerup = lpass_powerup,
+ .ramdump = lpass_ramdump,
+ .crash_shutdown = lpass_crash_shutdown
+};
+
+static int __init lpass_restart_init(void)
+{
+ lpass_8974_dev = subsys_register(&lpass_8974);
+ if (IS_ERR(lpass_8974_dev))
+ return PTR_ERR(lpass_8974_dev);
+ return 0;
+}
+
+static int __init lpass_fatal_init(void)
+{
+ int ret;
+
+ ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, 0);
+
+ if (ret < 0)
+ pr_err("%s: Unable to register SMSM callback! (%d)\n",
+ __func__, ret);
+
+ ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "q6_wdog", NULL);
+
+ if (ret < 0) {
+ pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
+ __func__);
+ goto out;
+ }
+ ret = lpass_restart_init();
+ if (ret < 0) {
+ pr_err("%s: Unable to reg with lpass ssr. (%d)\n",
+ __func__, ret);
+ goto out;
+ }
+
+ lpass_ssr_8974.lpass_ramdump_dev = create_ramdump_device("lpass");
+
+ if (!lpass_ssr_8974.lpass_ramdump_dev) {
+ pr_err("%s: Unable to create ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+ ssr_notif_hdle = subsys_notif_register_notifier("riva",
+ &rnb);
+ if (IS_ERR(ssr_notif_hdle) < 0) {
+ ret = PTR_ERR(ssr_notif_hdle);
+ pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
+ __func__, ret);
+ free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+ goto out;
+ }
+
+ ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
+ &mnb);
+ if (IS_ERR(ssr_modem_notif_hdle) < 0) {
+ ret = PTR_ERR(ssr_modem_notif_hdle);
+ pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
+ __func__, ret);
+ subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
+ free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+ goto out;
+ }
+
+ pr_info("%s: lpass SSR driver init'ed.\n", __func__);
+out:
+ return ret;
+}
+
+static void __exit lpass_fatal_exit(void)
+{
+ subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
+ subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
+ subsys_unregister(lpass_8974_dev);
+ free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+}
+
+module_init(lpass_fatal_init);
+module_exit(lpass_fatal_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 3c9ef65..1a5924d 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -85,6 +85,9 @@
REGULATOR_SUPPLY("cam_vdig", "4-0020"),
REGULATOR_SUPPLY("8921_l12", NULL),
};
+VREG_CONSUMERS(L13) = {
+ REGULATOR_SUPPLY("8921_l13", NULL),
+};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8921_l14", NULL),
};
@@ -657,6 +660,7 @@
RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL, 0, 0),
RPM_LDO(L11, 0, 1, 0, 3000000, 3000000, NULL, 0, 0),
RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
+ RPM_LDO(L13, 0, 0, 0, 2220000, 2220000, NULL, 0, 0),
RPM_LDO(L14, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
RPM_LDO(L16, 0, 1, 0, 2800000, 2800000, NULL, 0, 0),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 47a5a08..2a02450 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -887,7 +887,7 @@
};
static int phy_init_seq[] = {
- 0x38, 0x81, /* update DC voltage level */
+ 0x68, 0x81, /* update DC voltage level */
0x24, 0x82, /* set pre-emphasis and rise/fall time */
-1
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 7760f07..49fa168 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -76,7 +76,7 @@
#include <mach/msm_xo.h>
#include <mach/restart.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <mach/ion.h>
#include <mach/mdm2.h>
#include <mach/msm_rtb.h>
@@ -1451,7 +1451,7 @@
static int hsusb_phy_init_seq[] = {
0x44, 0x80, /* set VBUS valid threshold
and disconnect valid threshold */
- 0x38, 0x81, /* update DC voltage level */
+ 0x68, 0x81, /* update DC voltage level */
0x24, 0x82, /* set preemphasis and rise/fall time */
0x13, 0x83, /* set source impedance adjusment */
-1};
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index a3de539..2cd654c 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1434,7 +1434,7 @@
static int wr_phy_init_seq[] = {
0x44, 0x80, /* set VBUS valid threshold
and disconnect valid threshold */
- 0x38, 0x81, /* update DC voltage level */
+ 0x68, 0x81, /* update DC voltage level */
0x14, 0x82, /* set preemphasis and rise/fall time */
0x13, 0x83, /* set source impedance adjusment */
-1};
@@ -1442,7 +1442,7 @@
static int liquid_v1_phy_init_seq[] = {
0x44, 0x80,/* set VBUS valid threshold
and disconnect valid threshold */
- 0x3C, 0x81,/* update DC voltage level */
+ 0x6C, 0x81,/* update DC voltage level */
0x18, 0x82,/* set preemphasis and rise/fall time */
0x23, 0x83,/* set source impedance sdjusment */
-1};
@@ -1450,7 +1450,7 @@
static int sglte_phy_init_seq[] = {
0x44, 0x80, /* set VBUS valid threshold
and disconnect valid threshold */
- 0x3A, 0x81, /* update DC voltage level */
+ 0x6A, 0x81, /* update DC voltage level */
0x24, 0x82, /* set preemphasis and rise/fall time */
0x13, 0x83, /* set source impedance adjusment */
-1};
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index fd2329f..b385db5 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -60,6 +60,19 @@
},
};
#endif
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_8MA,
@@ -411,6 +424,43 @@
},
},
};
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+};
static struct msm_gpiomux_config msm_taiko_config[] __initdata = {
{
@@ -435,6 +485,8 @@
msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
#endif
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(msm8974_slimbus_config,
ARRAY_SIZE(msm8974_slimbus_config));
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index e599739..4523cf7 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -29,7 +29,7 @@
#include <linux/power/ltc4088-charger.h>
#include <linux/gpio.h>
#include <linux/msm_tsens.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <linux/memory.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -612,7 +612,7 @@
static int shelby_phy_init_seq[] = {
0x44, 0x80,/* set VBUS valid threshold and
disconnect valid threshold */
- 0x38, 0x81, /* update DC voltage level */
+ 0x68, 0x81, /* update DC voltage level */
0x24, 0x82,/* set preemphasis and rise/fall time */
0x13, 0x83,/* set source impedance adjustment */
-1};
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index d1d85fc..7a1e2ff 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -397,7 +397,9 @@
}
if (machine_is_msm8625_evb() || machine_is_msm7627a_evb()
- || machine_is_msm8625_evt()) {
+ || machine_is_msm8625_evt()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7()) {
sensor_board_info_ov7692.cam_vreg =
ov7692_gpio_vreg;
sensor_board_info_ov7692.num_vreg =
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 0949c5f..79f213e 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -336,6 +336,10 @@
goto set_gpio_fail;
}
gpio_free(gpio_wlan_sys_rest_en);
+ } else {
+ pr_err("%s: WLAN sys_rest_en GPIO %d request failed %d\n",
+ __func__, gpio_wlan_sys_rest_en, rc);
+ goto out;
}
}
@@ -373,6 +377,7 @@
gpio_free(GPIO_WLAN_3V3_EN);
reg_disable:
wlan_switch_regulators(0);
+out:
pr_info("WLAN power-down failed\n");
return rc;
}
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 8df1c9b..3d92a72 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -49,7 +49,7 @@
#include <linux/smsc911x.h>
#include <linux/atmel_maxtouch.h>
#include <linux/msm_adc.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include "devices.h"
#include "timer.h"
#include "board-msm7x27a-regulator.h"
@@ -164,7 +164,7 @@
#define MSM_PMEM_ADSP_SIZE 0x1200000
#define MSM7x25A_MSM_PMEM_ADSP_SIZE 0xB91000
-
+#define CAMERA_ZSL_SIZE (SZ_1M * 60)
#endif
#ifdef CONFIG_ION_MSM
@@ -748,6 +748,9 @@
pmem_mdp_size = MSM_PMEM_MDP_SIZE;
pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
}
+
+ if (get_ddr_size() > SZ_512M)
+ pmem_adsp_size = CAMERA_ZSL_SIZE;
#ifdef CONFIG_ION_MSM
msm_ion_camera_size = pmem_adsp_size;
msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 47d847e..281d055 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -103,7 +103,7 @@
#include "pm-boot.h"
#include "board-storage-common-a.h"
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <mach/ion.h>
#include <mach/msm_rtb.h>
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 58cb4ab..524a2ad 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -32,7 +32,7 @@
#include <linux/input/ft5x06_ts.h>
#include <linux/msm_adc.h>
#include <linux/regulator/msm-gpio-regulator.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -132,6 +132,7 @@
#ifdef CONFIG_ARCH_MSM7X27A
#define MSM_PMEM_MDP_SIZE 0x1B00000
#define MSM_PMEM_ADSP_SIZE 0x1200000
+#define CAMERA_ZSL_SIZE (SZ_1M * 60)
#ifdef CONFIG_ION_MSM
#define MSM_ION_HEAP_NUM 4
@@ -715,6 +716,8 @@
static void fix_sizes(void)
{
+ if (get_ddr_size() > SZ_512M)
+ pmem_adsp_size = CAMERA_ZSL_SIZE;
#ifdef CONFIG_ION_MSM
msm_ion_camera_size = pmem_adsp_size;
msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 373cf47..2ec4e38 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -2883,6 +2883,7 @@
};
struct pix_rdi_clk {
+ bool prepared;
bool enabled;
unsigned long cur_rate;
@@ -2908,6 +2909,7 @@
unsigned long flags;
struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
struct clk **mux_map = pix_rdi_mux_map;
+ unsigned long old_rate = rdi->cur_rate;
/*
* These clocks select three inputs via two muxes. One mux selects
@@ -2918,7 +2920,7 @@
* needs to be on at what time.
*/
for (i = 0; mux_map[i]; i++) {
- ret = clk_enable(mux_map[i]);
+ ret = clk_prepare_enable(mux_map[i]);
if (ret)
goto err;
}
@@ -2927,11 +2929,21 @@
goto err;
}
/* Keep the new source on when switching inputs of an enabled clock */
- if (rdi->enabled) {
- clk_disable(mux_map[rdi->cur_rate]);
- clk_enable(mux_map[rate]);
+ if (rdi->prepared) {
+ ret = clk_prepare(mux_map[rate]);
+ if (ret)
+ goto err;
}
- spin_lock_irqsave(&local_clock_reg_lock, flags);
+ spin_lock_irqsave(&c->lock, flags);
+ if (rdi->enabled) {
+ ret = clk_enable(mux_map[rate]);
+ if (ret) {
+ spin_unlock_irqrestore(&c->lock, flags);
+ clk_unprepare(mux_map[rate]);
+ goto err;
+ }
+ }
+ spin_lock(&local_clock_reg_lock);
reg = readl_relaxed(rdi->s2_reg);
reg &= ~rdi->s2_mask;
reg |= rate == 2 ? rdi->s2_mask : 0;
@@ -2953,10 +2965,16 @@
mb();
udelay(1);
rdi->cur_rate = rate;
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+ spin_unlock(&local_clock_reg_lock);
+
+ if (rdi->enabled)
+ clk_disable(mux_map[old_rate]);
+ spin_unlock_irqrestore(&c->lock, flags);
+ if (rdi->prepared)
+ clk_unprepare(mux_map[old_rate]);
err:
for (i--; i >= 0; i--)
- clk_disable(mux_map[i]);
+ clk_disable_unprepare(mux_map[i]);
return 0;
}
@@ -2966,6 +2984,13 @@
return to_pix_rdi_clk(c)->cur_rate;
}
+static int pix_rdi_clk_prepare(struct clk *c)
+{
+ struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+ rdi->prepared = true;
+ return 0;
+}
+
static int pix_rdi_clk_enable(struct clk *c)
{
unsigned long flags;
@@ -2990,6 +3015,12 @@
rdi->enabled = false;
}
+static void pix_rdi_clk_unprepare(struct clk *c)
+{
+ struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+ rdi->prepared = false;
+}
+
static int pix_rdi_clk_reset(struct clk *c, enum clk_reset_action action)
{
return branch_reset(&to_pix_rdi_clk(c)->b, action);
@@ -3026,8 +3057,10 @@
}
static struct clk_ops clk_ops_pix_rdi_8960 = {
+ .prepare = pix_rdi_clk_prepare,
.enable = pix_rdi_clk_enable,
.disable = pix_rdi_clk_disable,
+ .unprepare = pix_rdi_clk_unprepare,
.handoff = pix_rdi_clk_handoff,
.set_rate = pix_rdi_clk_set_rate,
.get_rate = pix_rdi_clk_get_rate,
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index e7f5b53..32445ed 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -526,7 +526,7 @@
#define dsipll_750_mm_source_val 1
#define dsipll0_byte_mm_source_val 1
#define dsipll0_pixel_mm_source_val 1
-#define hdmipll_297_mm_source_val 3
+#define hdmipll_mm_source_val 3
#define F(f, s, div, m, n) \
{ \
@@ -550,6 +550,17 @@
| BVAL(10, 8, s##_mm_source_val), \
}
+#define F_HDMI(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s##_clk_src, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
#define F_MDSS(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -638,13 +649,13 @@
#define OXILI_ID 0x1
#define OCMEM_ID 0x2
-enum {
- D0_ID = 1,
- D1_ID,
- A0_ID,
- A1_ID,
- A2_ID,
-};
+#define D0_ID 1
+#define D1_ID 2
+#define A0_ID 3
+#define A1_ID 4
+#define A2_ID 5
+#define DIFF_CLK_ID 7
+#define DIV_CLK_ID 11
DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
@@ -667,6 +678,8 @@
DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a0, cxo_a0_a, A0_ID);
DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a1, cxo_a1_a, A1_ID);
DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a2, cxo_a2_a, A2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk, div_a_clk, DIV_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk, diff_a_clk, DIFF_CLK_ID);
DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d0_pin, cxo_d0_a_pin, D0_ID);
DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d1_pin, cxo_d1_a_pin, D1_ID);
@@ -1987,9 +2000,9 @@
.en_mask = BIT(0),
.base = &virt_bases[GCC_BASE],
.c = {
- .dbg_name = "gcc_ce1_ahb_clk",
+ .dbg_name = "gcc_ce2_ahb_clk",
.ops = &clk_ops_vote,
- CLK_INIT(gcc_ce1_ahb_clk.c),
+ CLK_INIT(gcc_ce2_ahb_clk.c),
},
};
@@ -1999,7 +2012,7 @@
.en_mask = BIT(1),
.base = &virt_bases[GCC_BASE],
.c = {
- .dbg_name = "gcc_ce1_axi_clk",
+ .dbg_name = "gcc_ce2_axi_clk",
.ops = &clk_ops_vote,
CLK_INIT(gcc_ce2_axi_clk.c),
},
@@ -2382,7 +2395,7 @@
.dbg_name = "axi_clk_src",
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 282000000,
- HIGH, 320000000),
+ HIGH, 400000000),
CLK_INIT(axi_clk_src.c),
},
};
@@ -2996,14 +3009,85 @@
},
};
+static int hdmi_pll_clk_enable(struct clk *c)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ ret = hdmi_pll_enable();
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+ return ret;
+}
+
+static void hdmi_pll_clk_disable(struct clk *c)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ hdmi_pll_disable();
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ rc = hdmi_pll_set_rate(rate);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return rc;
+}
+
+static struct clk *hdmi_pll_clk_get_parent(struct clk *c)
+{
+ return &cxo_clk_src.c;
+}
+
+static struct clk_ops clk_ops_hdmi_pll = {
+ .enable = hdmi_pll_clk_enable,
+ .disable = hdmi_pll_clk_disable,
+ .set_rate = hdmi_pll_clk_set_rate,
+ .get_parent = hdmi_pll_clk_get_parent,
+};
+
+static struct clk hdmipll_clk_src = {
+ .dbg_name = "hdmipll_clk_src",
+ .ops = &clk_ops_hdmi_pll,
+ CLK_INIT(hdmipll_clk_src),
+ .warned = true,
+};
+
static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
- F_MDSS(148500000, hdmipll_297, 2, 0, 0),
+ /*
+ * The zero rate is required since suspend/resume wipes out the HDMI PHY
+ * registers. This entry allows the HDMI driver to switch the cached
+ * rate to zero before suspend and back to the real rate after resume.
+ */
+ F_HDMI( 0, hdmipll, 1, 0, 0),
+ F_HDMI( 25200000, hdmipll, 1, 0, 0),
+ F_HDMI( 27030000, hdmipll, 1, 0, 0),
+ F_HDMI( 74250000, hdmipll, 1, 0, 0),
+ F_HDMI(148500000, hdmipll, 1, 0, 0),
+ F_HDMI(297000000, hdmipll, 1, 0, 0),
F_END
};
+/*
+ * Unlike other clocks, the HDMI rate is adjusted through PLL
+ * re-programming. It is also routed through an HID divider.
+ */
+static void set_rate_hdmi(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+{
+ clk_set_rate(nf->src_clk, nf->freq_hz);
+ set_rate_hid(rcg, nf);
+}
+
static struct rcg_clk extpclk_clk_src = {
.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
- .set_rate = set_rate_hid,
+ .set_rate = set_rate_hdmi,
.freq_tbl = ftbl_mdss_extpclk_clk,
.current_freq = &rcg_dummy_freq,
.base = &virt_bases[MMSS_BASE],
@@ -4966,6 +5050,7 @@
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-lpass"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-mss"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-mba"),
+ CLK_LOOKUP("xo", cxo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil_pronto"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
@@ -5013,6 +5098,7 @@
CLK_LOOKUP("core_clk", gcc_blsp2_uart5_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_uart6_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, ""),
CLK_LOOKUP("core_clk", gcc_ce1_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_ce2_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, ""),
@@ -5062,6 +5148,7 @@
CLK_LOOKUP("sleep_clk", gcc_usb30_sleep_clk.c, "msm_dwc3"),
CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
CLK_LOOKUP("sleep_b_clk", gcc_usb2b_phy_sleep_clk.c, "msm_dwc3"),
+ CLK_LOOKUP("ref_clk", diff_clk.c, "msm_dwc3"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "msm_otg"),
CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, "msm_hsic_host"),
@@ -5090,9 +5177,9 @@
/* MM sensor clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
@@ -5126,30 +5213,52 @@
CLK_LOOKUP("csiphy_timer_clk", camss_phy2_csi2phytimer_clk.c,
"fda0b400.qcom,csiphy"),
/* CSID clocks */
- CLK_LOOKUP("csi_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi_clk", camss_csi1_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi_ahb_clk", camss_csi2_ahb_clk.c, "fda08800.qcom,csid"),
- CLK_LOOKUP("csi_src_clk", csi2_clk_src.c, "fda08800.qcom,csid"),
- CLK_LOOKUP("csi_phy_clk", camss_csi2phy_clk.c, "fda08800.qcom,csid"),
- CLK_LOOKUP("csi_clk", camss_csi2_clk.c, "fda08800.qcom,csid"),
- CLK_LOOKUP("csi_pix_clk", camss_csi2pix_clk.c, "fda08800.qcom,csid"),
- CLK_LOOKUP("csi_rdi_clk", camss_csi2rdi_clk.c, "fda08800.qcom,csid"),
- CLK_LOOKUP("csi_ahb_clk", camss_csi3_ahb_clk.c, "fda08c00.qcom,csid"),
- CLK_LOOKUP("csi_src_clk", csi3_clk_src.c, "fda08c00.qcom,csid"),
- CLK_LOOKUP("csi_phy_clk", camss_csi3phy_clk.c, "fda08c00.qcom,csid"),
- CLK_LOOKUP("csi_clk", camss_csi3_clk.c, "fda08c00.qcom,csid"),
- CLK_LOOKUP("csi_pix_clk", camss_csi3pix_clk.c, "fda08c00.qcom,csid"),
- CLK_LOOKUP("csi_rdi_clk", camss_csi3rdi_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
+
+ CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi1_clk", camss_csi1_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
+
+ CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi2_ahb_clk", camss_csi2_ahb_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi2_src_clk", csi2_clk_src.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi2_phy_clk", camss_csi2phy_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi2_clk", camss_csi2_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi2_pix_clk", camss_csi2pix_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08800.qcom,csid"),
+ CLK_LOOKUP("csi2_rdi_clk", camss_csi2rdi_clk.c, "fda08800.qcom,csid"),
+
+ CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi3_ahb_clk", camss_csi3_ahb_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi3_src_clk", csi3_clk_src.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi3_phy_clk", camss_csi3phy_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi3_clk", camss_csi3_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi3_pix_clk", camss_csi3pix_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08c00.qcom,csid"),
+ CLK_LOOKUP("csi3_rdi_clk", camss_csi3rdi_clk.c, "fda08c00.qcom,csid"),
+
/*VFE clocks*/
CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
"fda10000.qcom,vfe"),
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 2df1cd1..b952f2f 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -320,10 +320,6 @@
u32 reg_val;
void __iomem *const reg = rcg->b.ctl_reg;
- WARN(rcg->current_freq == &rcg_dummy_freq,
- "Attempting to enable %s before setting its rate. "
- "Set the rate first!\n", rcg->c.dbg_name);
-
/*
* Program the NS register, if applicable. NS registers are not
* set in the set_rate path because power can be saved by deferring
@@ -419,6 +415,18 @@
}
}
+static int rcg_clk_prepare(struct clk *c)
+{
+ struct rcg_clk *rcg = to_rcg_clk(c);
+
+ WARN(rcg->current_freq == &rcg_dummy_freq,
+ "Attempting to prepare %s before setting its rate. "
+ "Set the rate first!\n", rcg->c.dbg_name);
+ rcg->prepared = true;
+
+ return 0;
+}
+
/* Enable a rate-settable clock. */
static int rcg_clk_enable(struct clk *c)
{
@@ -445,6 +453,12 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
+static void rcg_clk_unprepare(struct clk *c)
+{
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ rcg->prepared = false;
+}
+
/*
* Frequency-related functions
*/
@@ -456,6 +470,7 @@
struct clk_freq_tbl *nf, *cf;
struct clk *chld;
int rc = 0;
+ unsigned long flags;
for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
&& nf->freq_hz != rate; nf++)
@@ -466,11 +481,22 @@
cf = rcg->current_freq;
- if (rcg->enabled) {
- /* Enable source clock dependency for the new freq. */
- rc = clk_enable(nf->src_clk);
+ /* Enable source clock dependency for the new frequency */
+ if (rcg->prepared) {
+ rc = clk_prepare(nf->src_clk);
if (rc)
return rc;
+
+ }
+
+ spin_lock_irqsave(&c->lock, flags);
+ if (rcg->enabled) {
+ rc = clk_enable(nf->src_clk);
+ if (rc) {
+ spin_unlock_irqrestore(&c->lock, flags);
+ clk_unprepare(nf->src_clk);
+ return rc;
+ }
}
spin_lock(&local_clock_reg_lock);
@@ -519,6 +545,10 @@
/* Release source requirements of the old freq. */
if (rcg->enabled)
clk_disable(cf->src_clk);
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ if (rcg->prepared)
+ clk_unprepare(cf->src_clk);
return rc;
}
@@ -819,8 +849,10 @@
}
struct clk_ops clk_ops_rcg = {
+ .prepare = rcg_clk_prepare,
.enable = rcg_clk_enable,
.disable = rcg_clk_disable,
+ .unprepare = rcg_clk_unprepare,
.enable_hwcg = rcg_clk_enable_hwcg,
.disable_hwcg = rcg_clk_disable_hwcg,
.in_hwcg_mode = rcg_clk_in_hwcg_mode,
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 034e09c..81085ef 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -164,6 +164,7 @@
* Generic clock-definition struct and macros
*/
struct rcg_clk {
+ bool prepared;
bool enabled;
void *const ns_reg;
void *const md_reg;
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 42b36f6..3f19b2a 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -148,12 +148,12 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
-static int rcg_clk_enable(struct clk *c)
+static int rcg_clk_prepare(struct clk *c)
{
struct rcg_clk *rcg = to_rcg_clk(c);
WARN(rcg->current_freq == &rcg_dummy_freq,
- "Attempting to enable %s before setting its rate. "
+ "Attempting to prepare %s before setting its rate. "
"Set the rate first!\n", rcg->c.dbg_name);
return 0;
@@ -163,7 +163,8 @@
{
struct clk_freq_tbl *cf, *nf;
struct rcg_clk *rcg = to_rcg_clk(c);
- int rc = 0;
+ int rc;
+ unsigned long flags;
for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
&& nf->freq_hz != rate; nf++)
@@ -174,12 +175,21 @@
cf = rcg->current_freq;
- if (rcg->c.count) {
- /* TODO: Modify to use the prepare API */
- /* Enable source clock dependency for the new freq. */
- rc = clk_enable(nf->src_clk);
+ /* Enable source clock dependency for the new freq. */
+ if (c->prepare_count) {
+ rc = clk_prepare(nf->src_clk);
if (rc)
- goto out;
+ return rc;
+ }
+
+ spin_lock_irqsave(&c->lock, flags);
+ if (c->count) {
+ rc = clk_enable(nf->src_clk);
+ if (rc) {
+ spin_unlock_irqrestore(&c->lock, flags);
+ clk_unprepare(nf->src_clk);
+ return rc;
+ }
}
BUG_ON(!rcg->set_rate);
@@ -188,12 +198,16 @@
rcg->set_rate(rcg, nf);
/* Release source requirements of the old freq. */
- if (rcg->c.count)
+ if (c->count)
clk_disable(cf->src_clk);
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ if (c->prepare_count)
+ clk_unprepare(cf->src_clk);
rcg->current_freq = nf;
-out:
- return rc;
+
+ return 0;
}
/* Return a supported rate that's at least the specified rate. */
@@ -585,7 +599,7 @@
struct clk_ops clk_ops_empty;
struct clk_ops clk_ops_rcg = {
- .enable = rcg_clk_enable,
+ .enable = rcg_clk_prepare,
.set_rate = rcg_clk_set_rate,
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
@@ -594,7 +608,7 @@
};
struct clk_ops clk_ops_rcg_mnd = {
- .enable = rcg_clk_enable,
+ .enable = rcg_clk_prepare,
.set_rate = rcg_clk_set_rate,
.list_rate = rcg_clk_list_rate,
.round_rate = rcg_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 4cd9b1c..3e1cbb9 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -12,13 +12,13 @@
*/
#include <linux/err.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/clk.h>
#include "clock.h"
#include "clock-voter.h"
-static DEFINE_SPINLOCK(voter_clk_lock);
+static DEFINE_MUTEX(voter_clk_lock);
/* Aggregate the rate of clocks that are currently on. */
static unsigned long voter_clk_aggregate_rate(const struct clk *parent)
@@ -37,12 +37,11 @@
static int voter_clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret = 0;
- unsigned long flags;
struct clk *clkp;
struct clk_voter *clkh, *v = to_clk_voter(clk);
unsigned long cur_rate, new_rate, other_rate = 0;
- spin_lock_irqsave(&voter_clk_lock, flags);
+ mutex_lock(&voter_clk_lock);
if (v->enabled) {
struct clk *parent = v->parent;
@@ -68,20 +67,19 @@
}
clk->rate = rate;
unlock:
- spin_unlock_irqrestore(&voter_clk_lock, flags);
+ mutex_unlock(&voter_clk_lock);
return ret;
}
-static int voter_clk_enable(struct clk *clk)
+static int voter_clk_prepare(struct clk *clk)
{
int ret = 0;
- unsigned long flags;
unsigned long cur_rate;
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- spin_lock_irqsave(&voter_clk_lock, flags);
+ mutex_lock(&voter_clk_lock);
parent = v->parent;
/*
@@ -96,18 +94,18 @@
}
v->enabled = true;
out:
- spin_unlock_irqrestore(&voter_clk_lock, flags);
+ mutex_unlock(&voter_clk_lock);
return ret;
}
-static void voter_clk_disable(struct clk *clk)
+static void voter_clk_unprepare(struct clk *clk)
{
- unsigned long flags, cur_rate, new_rate;
+ unsigned long cur_rate, new_rate;
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- spin_lock_irqsave(&voter_clk_lock, flags);
+ mutex_lock(&voter_clk_lock);
parent = v->parent;
/*
@@ -121,7 +119,7 @@
if (new_rate < cur_rate)
clk_set_rate(parent, new_rate);
- spin_unlock_irqrestore(&voter_clk_lock, flags);
+ mutex_unlock(&voter_clk_lock);
}
static int voter_clk_is_enabled(struct clk *clk)
@@ -157,8 +155,8 @@
}
struct clk_ops clk_ops_voter = {
- .enable = voter_clk_enable,
- .disable = voter_clk_disable,
+ .prepare = voter_clk_prepare,
+ .unprepare = voter_clk_unprepare,
.set_rate = voter_clk_set_rate,
.is_enabled = voter_clk_is_enabled,
.round_rate = voter_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index f605c1f..a0367b0 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -156,6 +156,9 @@
if (ret)
goto err_prepare_depends;
+ ret = vote_rate_vdd(clk, clk->rate);
+ if (ret)
+ goto err_vote_vdd;
if (clk->ops->prepare)
ret = clk->ops->prepare(clk);
if (ret)
@@ -166,6 +169,8 @@
mutex_unlock(&clk->prepare_lock);
return ret;
err_prepare_clock:
+ unvote_rate_vdd(clk, clk->rate);
+err_vote_vdd:
clk_unprepare(clk->depends);
err_prepare_depends:
clk_unprepare(parent);
@@ -202,9 +207,6 @@
if (ret)
goto err_enable_depends;
- ret = vote_rate_vdd(clk, clk->rate);
- if (ret)
- goto err_vote_vdd;
trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
if (clk->ops->enable)
ret = clk->ops->enable(clk);
@@ -217,8 +219,6 @@
return 0;
err_enable_clock:
- unvote_rate_vdd(clk, clk->rate);
-err_vote_vdd:
clk_disable(clk->depends);
err_enable_depends:
clk_disable(parent);
@@ -249,7 +249,6 @@
trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
if (clk->ops->disable)
clk->ops->disable(clk);
- unvote_rate_vdd(clk, clk->rate);
clk_disable(clk->depends);
clk_disable(parent);
}
@@ -281,6 +280,7 @@
if (clk->ops->unprepare)
clk->ops->unprepare(clk);
+ unvote_rate_vdd(clk, clk->rate);
clk_unprepare(clk->depends);
clk_unprepare(parent);
}
@@ -316,7 +316,7 @@
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- unsigned long start_rate, flags;
+ unsigned long start_rate;
int rc = 0;
if (IS_ERR_OR_NULL(clk))
@@ -325,14 +325,14 @@
if (!clk->ops->set_rate)
return -ENOSYS;
- spin_lock_irqsave(&clk->lock, flags);
+ mutex_lock(&clk->prepare_lock);
/* Return early if the rate isn't going to change */
if (clk->rate == rate)
goto out;
- trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
- if (clk->count) {
+ trace_clock_set_rate(clk->dbg_name, rate, raw_smp_processor_id());
+ if (clk->prepare_count) {
start_rate = clk->rate;
/* Enforce vdd requirements for target frequency. */
rc = vote_rate_vdd(clk, rate);
@@ -350,14 +350,13 @@
if (!rc)
clk->rate = rate;
out:
- spin_unlock_irqrestore(&clk->lock, flags);
+ mutex_unlock(&clk->prepare_lock);
return rc;
err_set_rate:
unvote_rate_vdd(clk, rate);
err_vote_vdd:
- spin_unlock_irqrestore(&clk->lock, flags);
- return rc;
+ goto out;
}
EXPORT_SYMBOL(clk_set_rate);
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index a3a1574..dd2dc1d 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -81,7 +81,7 @@
#endif
pm_mode = msm_pm_idle_prepare(dev, drv, index);
- msm_pm_idle_enter(pm_mode);
+ dev->last_residency = msm_pm_idle_enter(pm_mode);
for (i = 0; i < dev->state_count; i++) {
st_usage = &dev->states_usage[i];
if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 5fc4806..1ef8793 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -36,7 +36,7 @@
#include <mach/msm_smd.h>
#include <mach/msm_dcvs.h>
#include <mach/msm_rtb.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include "clock.h"
#include "devices.h"
#include "footswitch.h"
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 867e8fc..dfef866 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <asm/io.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <mach/msm_iomap.h>
#include <mach/irqs-8930.h>
#include <mach/rpm.h>
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index c12c0f7..b456f50 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -26,7 +26,7 @@
#include <mach/dma.h>
#include <mach/board.h>
#include <asm/clkdev.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include "devices.h"
#include "footswitch.h"
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index d086753..7bffd9b 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <mach/irqs.h>
#include <mach/dma.h>
#include <asm/mach/mmc.h>
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index a7dc730..d4d2fca 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -177,6 +177,7 @@
struct msm_camera_csi_lane_params {
uint16_t csi_lane_assign;
uint16_t csi_lane_mask;
+ uint8_t csi_phy_sel;
};
struct msm_camera_gpio_conf {
diff --git a/arch/arm/mach-msm/include/mach/msm_bus.h b/arch/arm/mach-msm/include/mach/msm_bus.h
index 6d7a533..c94bf80 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/input.h>
+#include <linux/platform_device.h>
/*
* Macros for clients to convert their data to ib and ab
@@ -77,11 +78,24 @@
uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
void msm_bus_scale_unregister_client(uint32_t cl);
+struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev);
+void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata);
/* AXI Port configuration APIs */
int msm_bus_axi_porthalt(int master_port);
int msm_bus_axi_portunhalt(int master_port);
#else
+static inline struct msm_bus_scale_pdata
+*msm_bus_cl_get_pdata(struct platform_device *pdev)
+{
+ return NULL;
+}
+
+static inline void
+msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
+{
+}
+
static inline uint32_t
msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
{
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
index 7f04be8..15be294 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -54,4 +54,13 @@
#define MSM_DEBUG_UART_PHYS 0xF991E000
#endif
+/*
+ * IMEM is retained for secure watchdog reset
+ * Debug Image looks at actual IMEM to
+ * do memory dumping.
+ */
+
+#define MSM8974_DBG_IMEM_PHYS 0xFE805000
+#define MSM8974_DBG_IMEM_SIZE SZ_4K
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index e961dfc..2205b3b 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -97,6 +97,7 @@
#define MSM_MDC_BASE IOMEM(0xFA400000) /* 1M */
#define MSM_AD5_BASE IOMEM(0xFA900000) /* 13M (D00000)
0xFB600000 */
+#define MSM_DBG_IMEM_BASE IOMEM(0xFB600000) /* 4K */
#define MSM_STRONGLY_ORDERED_PAGE 0xFA0F0000
#define MSM8625_SECONDARY_PHYS 0x0FE00000
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
index b96640d..d2905d4 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -25,6 +25,7 @@
unsigned char inject_rx_on_wakeup;
char rx_to_inject;
int (*gpio_config)(int);
+ int userid;
};
unsigned int msm_hs_tx_empty(struct uart_port *uport);
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 47f9b10..09dfac0 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -90,9 +90,10 @@
/* Operational modes of each region */
enum region_mode {
- WIDE_MODE = 0x0,
+ MODE_NOT_SET = 0x0,
+ WIDE_MODE,
THIN_MODE,
- MODE_DEFAULT = WIDE_MODE,
+ MODE_DEFAULT = MODE_NOT_SET,
};
struct ocmem_plat_data {
@@ -101,6 +102,7 @@
unsigned long base;
struct clk *core_clk;
struct clk *iface_clk;
+ struct clk *br_clk;
struct ocmem_partition *parts;
int nr_parts;
void __iomem *reg_base;
@@ -198,11 +200,17 @@
int process_shrink(int, struct ocmem_handle *, unsigned long);
int ocmem_rdm_transfer(int, struct ocmem_map_list *,
unsigned long, int);
+int ocmem_clear(unsigned long, unsigned long);
unsigned long process_quota(int);
int ocmem_memory_off(int, unsigned long, unsigned long);
int ocmem_memory_on(int, unsigned long, unsigned long);
int ocmem_enable_core_clock(void);
int ocmem_enable_iface_clock(void);
+int ocmem_enable_br_clock(void);
void ocmem_disable_core_clock(void);
void ocmem_disable_iface_clock(void);
+void ocmem_disable_br_clock(void);
+int ocmem_lock(enum ocmem_client, unsigned long, unsigned long,
+ enum region_mode);
+int ocmem_unlock(enum ocmem_client, unsigned long, unsigned long);
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
index 6de47bd..abcdbb8 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
@@ -100,6 +100,7 @@
RPM_VREG_ID_PM8921_L10,
RPM_VREG_ID_PM8921_L11,
RPM_VREG_ID_PM8921_L12,
+ RPM_VREG_ID_PM8921_L13,
RPM_VREG_ID_PM8921_L14,
RPM_VREG_ID_PM8921_L15,
RPM_VREG_ID_PM8921_L16,
@@ -176,6 +177,7 @@
};
/* Minimum high power mode loads in uA. */
+#define RPM_VREG_8960_LDO_5_HPM_MIN_LOAD 0
#define RPM_VREG_8960_LDO_50_HPM_MIN_LOAD 5000
#define RPM_VREG_8960_LDO_150_HPM_MIN_LOAD 10000
#define RPM_VREG_8960_LDO_300_HPM_MIN_LOAD 10000
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 6d15f47..d3c4eb8 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -27,8 +27,21 @@
RESET_LEVEL_MAX
};
+struct device;
+struct module;
+
+/**
+ * struct subsys_desc - subsystem descriptor
+ * @name: name of subsystem
+ * @depends_on: subsystem this subsystem depends on to operate
+ * @dev: parent device
+ * @owner: module the descriptor belongs to
+ */
struct subsys_desc {
const char *name;
+ const char *depends_on;
+ struct device *dev;
+ struct module *owner;
int (*shutdown)(const struct subsys_desc *desc);
int (*powerup)(const struct subsys_desc *desc);
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a2e46ca..b29149f 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -310,6 +310,7 @@
#ifdef CONFIG_DEBUG_MSM8974_UART
MSM_DEVICE(DEBUG_UART),
#endif
+ MSM_CHIP_DEVICE(DBG_IMEM, MSM8974),
};
void __init msm_map_8974_io(void)
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index bf5857c..3b7c5d6 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -1070,6 +1070,20 @@
cpu = raw_smp_processor_id();
+ /* Attempt restore only if save has been done. If power collapse
+ * is disabled, hotplug off of non-boot core will result in WFI
+ * and hence msm_jtag_save_state will not occur. Subsequently,
+ * during hotplug on of non-boot core when msm_jtag_restore_state
+ * is called via msm_platform_secondary_init, this check will help
+ * bail us out without restoring.
+ */
+ if (msm_jtag_save_cntr[cpu] == msm_jtag_restore_cntr[cpu])
+ return;
+ else if (msm_jtag_save_cntr[cpu] != msm_jtag_restore_cntr[cpu] + 1)
+ pr_err_ratelimited("jtag imbalance, save:%lu, restore:%lu\n",
+ (unsigned long)msm_jtag_save_cntr[cpu],
+ (unsigned long)msm_jtag_restore_cntr[cpu]);
+
msm_jtag_restore_cntr[cpu]++;
/* ensure counter is updated before moving forward */
mb();
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
new file mode 100644
index 0000000..fec578f
--- /dev/null
+++ b/arch/arm/mach-msm/modem-ssr-8974.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+
+static int crash_shutdown;
+static struct subsys_device *modem_ssr_dev;
+
+#define MAX_SSR_REASON_LEN 81U
+#define Q6SS_WDOG_ENABLE 0xFC802004
+#define MSS_Q6SS_WDOG_EXP_IRQ 56
+
+static void log_modem_sfr(void)
+{
+ u32 size;
+ char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+ smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ if (!smem_reason || !size) {
+ pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
+ return;
+ }
+
+ strlcpy(reason, smem_reason, min(size, sizeof(reason)));
+ pr_err("modem subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void restart_modem(void)
+{
+ log_modem_sfr();
+ subsystem_restart("modem");
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("Probable fatal error on the modem.\n");
+ restart_modem();
+ }
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+ return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+ return 0;
+}
+
+void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+ crash_shutdown = 1;
+ smsm_reset_modem(SMSM_RESET);
+}
+
+static int modem_ramdump(int enable,
+ const struct subsys_desc *crashed_subsys)
+{
+ return 0;
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+ pr_err("Watchdog bite received from modem software!\n");
+ restart_modem();
+ return IRQ_HANDLED;
+}
+
+static struct subsys_desc modem_8974 = {
+ .name = "modem",
+ .shutdown = modem_shutdown,
+ .powerup = modem_powerup,
+ .ramdump = modem_ramdump,
+ .crash_shutdown = modem_crash_shutdown
+};
+
+static int __init modem_8974_init(void)
+{
+ int ret;
+
+ ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, 0);
+
+ if (ret < 0) {
+ pr_err("%s: Unable to register SMSM callback! (%d)\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ret = request_irq(MSS_Q6SS_WDOG_EXP_IRQ, modem_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
+
+ if (ret < 0) {
+ pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
+ __func__, ret);
+ goto out;
+ }
+
+ modem_ssr_dev = subsys_register(&modem_8974);
+
+ if (IS_ERR_OR_NULL(modem_ssr_dev)) {
+ pr_err("%s: Unable to reg with subsystem restart. (%ld)\n",
+ __func__, PTR_ERR(modem_ssr_dev));
+ ret = PTR_ERR(modem_ssr_dev);
+ goto out;
+ }
+
+ pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
+out:
+ return ret;
+}
+
+arch_initcall(modem_8974_init);
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index 924577f..bdc6fac 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -2,7 +2,7 @@
# Makefile for msm-bus driver specific files
#
obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o
-obj-y += msm_bus_bimc.o msm_bus_noc.o
+obj-y += msm_bus_bimc.o msm_bus_noc.o msm_bus_of.o
obj-$(CONFIG_MSM_RPM) += msm_bus_rpm.o
obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index 265716d..1b8c07e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -804,7 +804,7 @@
.num_tiers = ARRAY_SIZE(tier2),
.hw_sel = MSM_BUS_NOC,
.perm_mode = NOC_QOS_MODES_ALL_PERM,
- .mode = NOC_QOS_MODE_FIXED,
+ .mode = NOC_QOS_MODE_BYPASS,
.ws = 10000,
.qport = qports_oxili,
.mas_hw_id = MAS_GFX3D,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index e6ec722..049e8c7 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -189,10 +189,10 @@
}
static void noc_set_qos_mode(struct msm_bus_noc_info *ninfo, uint32_t mport,
- uint8_t mode)
+ uint8_t mode, uint8_t perm_mode)
{
if (mode < NOC_QOS_MODE_MAX &&
- ((1 << mode) & ninfo->mas_modes[mport])) {
+ ((1 << mode) & perm_mode)) {
uint32_t reg_val;
reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
@@ -297,13 +297,13 @@
}
uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
- uint32_t mport)
+ uint32_t mport, uint32_t mode, uint32_t perm_mode)
{
- if (NOC_QOS_MODES_ALL_PERM == ninfo->mas_modes[mport])
+ if (NOC_QOS_MODES_ALL_PERM == perm_mode)
return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
mport)) & NOC_QOS_MODEn_MODE_BMSK;
else
- return 31 - __CLZ(ninfo->mas_modes[mport] &
+ return 31 - __CLZ(mode &
NOC_QOS_MODES_ALL_PERM);
}
@@ -320,9 +320,9 @@
}
void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
- uint32_t mport, struct msm_bus_noc_qos_bw *qbw)
+ uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
{
- if (ninfo->mas_modes[mport] & (NOC_QOS_PERM_MODE_LIMITER |
+ if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
NOC_QOS_PERM_MODE_REGULATOR)) {
uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
base, mport)) & NOC_QOS_BWn_BW_BMSK;
@@ -375,7 +375,7 @@
}
noc_set_qos_mode(ninfo, info->node_info->qport[i], info->
- node_info->mode);
+ node_info->mode, info->node_info->perm_mode);
}
return 0;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
index 407d3ec..35af884 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
@@ -64,10 +64,10 @@
void msm_bus_noc_init(struct msm_bus_noc_info *ninfo);
uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
- uint32_t mport);
+ uint32_t mport, uint32_t mode, uint32_t perm_mode);
void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
uint32_t mport, struct msm_bus_noc_qos_priority *qprio);
void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
- uint32_t mport, struct msm_bus_noc_qos_bw *qbw);
+ uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw);
#endif /*_ARCH_ARM_MACH_MSM_BUS_NOC_H */
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
new file mode 100644
index 0000000..24b0ce2
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <mach/msm_bus.h>
+
+/**
+ * msm_bus_cl_get_pdata() - Generate bus client data from device tree
+ * provided by clients.
+ *
+ * of_node: Device tree node to extract information from
+ *
+ * The function returns a valid pointer to the allocated bus-scale-pdata
+ * if the vectors were correctly read from the client's device node.
+ * Any error in reading or parsing the device node will return NULL
+ * to the caller.
+ */
+struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev)
+{
+ struct device_node *of_node;
+ struct msm_bus_scale_pdata *pdata = NULL;
+ struct msm_bus_paths *usecase = NULL;
+ int i = 0, j, ret, num_usecases = 0, num_paths, len;
+ const uint32_t *vec_arr = NULL;
+ bool mem_err = false;
+
+ if (!pdev) {
+ pr_err("Error: Null Platform device\n");
+ return NULL;
+ }
+
+ of_node = pdev->dev.of_node;
+ pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_scale_pdata),
+ GFP_KERNEL);
+ if (!pdata) {
+ pr_err("Error: Memory allocation for pdata failed\n");
+ mem_err = true;
+ goto err;
+ }
+
+ ret = of_property_read_string(of_node, "qcom,msm_bus,name",
+ &pdata->name);
+ if (ret) {
+ pr_err("Error: Client name not found\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32(of_node, "qcom,msm_bus,num_cases",
+ &num_usecases);
+ if (ret) {
+ pr_err("Error: num_usecases not found\n");
+ goto err;
+ }
+
+ pdata->num_usecases = num_usecases;
+ ret = of_property_read_u32(of_node, "qcom,msm_bus,active_only",
+ &pdata->active_only);
+ if (ret) {
+ pr_info("active_only flag absent.\n");
+ pr_info("Using dual context by default\n");
+ }
+
+ usecase = devm_kzalloc(&pdev->dev, (sizeof(struct msm_bus_paths) *
+ pdata->num_usecases), GFP_KERNEL);
+ if (!usecase) {
+ pr_err("Error: Memory allocation for paths failed\n");
+ mem_err = true;
+ goto err;
+ }
+
+ ret = of_property_read_u32(of_node, "qcom,msm_bus,num_paths",
+ &num_paths);
+ if (ret) {
+ pr_err("Error: num_paths not found\n");
+ goto err;
+ }
+
+ vec_arr = of_get_property(of_node, "qcom,msm_bus,vectors", &len);
+ if (len != num_usecases * num_paths * sizeof(struct msm_bus_vectors)) {
+ pr_err("Error: Length-error on getting vectors\n");
+ goto err;
+ }
+
+ for (i = 0; i < num_usecases; i++) {
+ usecase[i].num_paths = num_paths;
+ usecase[i].vectors = devm_kzalloc(&pdev->dev, num_paths *
+ sizeof(struct msm_bus_vectors), GFP_KERNEL);
+ if (!usecase[i].vectors) {
+ mem_err = true;
+ pr_err("Error: Mem alloc failure in vectors\n");
+ goto err;
+ }
+
+ for (j = 0; j < num_paths; j++) {
+ int index = ((i * num_paths) + j) * 4;
+ usecase[i].vectors[j].src = be32_to_cpu(vec_arr[index]);
+ usecase[i].vectors[j].dst =
+ be32_to_cpu(vec_arr[index + 1]);
+ usecase[i].vectors[j].ab =
+ be32_to_cpu(vec_arr[index + 2]);
+ usecase[i].vectors[j].ib =
+ be32_to_cpu(vec_arr[index + 3]);
+ }
+ }
+
+ pdata->usecase = usecase;
+ return pdata;
+err:
+ if (mem_err) {
+ for (; i > 0; i--)
+ kfree(usecase[i-1].vectors);
+
+ kfree(usecase);
+ kfree(pdata);
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(msm_bus_cl_get_pdata);
+
+/**
+ * msm_bus_cl_clear_pdata() - Clear pdata allocated from device-tree
+ * of_node: Device tree node to extract information from
+ */
+void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
+{
+ int i;
+
+ for (i = 0; i < pdata->num_usecases; i++)
+ kfree(pdata->usecase[i].vectors);
+
+ kfree(pdata->usecase);
+ kfree(pdata);
+}
+EXPORT_SYMBOL(msm_bus_cl_clear_pdata);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 51445aa..793fcc5 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -372,6 +372,27 @@
pr_debug("ocmem: Disabled iface clock\n");
}
+/* Block-Remapper Clock Operations */
+int ocmem_enable_br_clock(void)
+{
+ int ret;
+
+ ret = clk_prepare_enable(ocmem_pdata->br_clk);
+
+ if (ret) {
+ pr_err("ocmem: Failed to enable br clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled br clock\n");
+ return 0;
+}
+
+void ocmem_disable_br_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->br_clk);
+ pr_debug("ocmem: Disabled br clock\n");
+}
+
static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -719,6 +740,7 @@
struct device *dev = &pdev->dev;
struct clk *ocmem_core_clk = NULL;
struct clk *ocmem_iface_clk = NULL;
+ struct clk *ocmem_br_clk = NULL;
if (!pdev->dev.of_node) {
dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -757,8 +779,16 @@
return PTR_ERR(ocmem_core_clk);
};
+ ocmem_br_clk = devm_clk_get(dev, "br_clk");
+
+ if (IS_ERR(ocmem_br_clk)) {
+ dev_err(dev, "Unable to get the BR clock\n");
+ return PTR_ERR(ocmem_br_clk);
+ }
+
ocmem_pdata->core_clk = ocmem_core_clk;
ocmem_pdata->iface_clk = ocmem_iface_clk;
+ ocmem_pdata->br_clk = ocmem_br_clk;
platform_set_drvdata(pdev, ocmem_pdata);
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index 2604d47..6e094fd 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -131,6 +131,7 @@
return __ocmem_allocate_range(client_id, size, size,
size, can_block, can_wait);
}
+EXPORT_SYMBOL(ocmem_allocate);
struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
{
@@ -162,6 +163,7 @@
return __ocmem_allocate_range(client_id, size, size,
size, can_block, can_wait);
}
+EXPORT_SYMBOL(ocmem_allocate_nowait);
struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
unsigned long goal, unsigned long step)
@@ -202,6 +204,7 @@
return __ocmem_allocate_range(client_id, min, goal,
step, can_block, can_wait);
}
+EXPORT_SYMBOL(ocmem_allocate_range);
struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
{
@@ -242,6 +245,7 @@
can_block, can_wait);
}
+EXPORT_SYMBOL(ocmem_allocate_nb);
int ocmem_free(int client_id, struct ocmem_buf *buffer)
{
@@ -263,6 +267,7 @@
return __ocmem_free(client_id, buffer);
}
+EXPORT_SYMBOL(ocmem_free);
int ocmem_shrink(int client_id, struct ocmem_buf *buffer, unsigned long len)
{
@@ -279,6 +284,7 @@
return __ocmem_shrink(client_id, buffer, len);
}
+EXPORT_SYMBOL(ocmem_shrink);
int pre_validate_chunk_list(struct ocmem_map_list *list)
{
@@ -350,6 +356,7 @@
mutex_unlock(&handle->handle_mutex);
return ret;
}
+EXPORT_SYMBOL(ocmem_map);
int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
struct ocmem_map_list *list)
@@ -390,6 +397,7 @@
mutex_unlock(&handle->handle_mutex);
return ret;
}
+EXPORT_SYMBOL(ocmem_unmap);
unsigned long get_max_quota(int client_id)
{
@@ -427,6 +435,7 @@
mutex_unlock(&ocmem_eviction_lock);
return ret;
}
+EXPORT_SYMBOL(ocmem_evict);
int ocmem_restore(int client_id)
{
@@ -448,6 +457,7 @@
mutex_unlock(&ocmem_eviction_lock);
return ret;
}
+EXPORT_SYMBOL(ocmem_restore);
/* Wrappers until power control is transitioned to clients */
enum ocmem_power_state ocmem_get_power_state(int client_id,
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index de9856d..5a85eec 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -38,6 +38,7 @@
unsigned psgsc_ctrl;
bool interleaved;
unsigned int mode;
+ atomic_t mode_counter;
unsigned int num_macros;
struct ocmem_hw_macro *macro;
struct msm_rpm_request *rpm_req;
@@ -57,10 +58,13 @@
#define OC_GEN_STATUS (0xC)
#define OC_PSGSC_STATUS (0x38)
#define OC_PSGSC_CTL (0x3C)
-#define OC_REGION_CTL (0x1000)
+#define OC_REGION_MODE_CTL (0x1000)
+#define OC_GFX_MPU_START (0x1004)
+#define OC_GFX_MPU_END (0x1008)
#define NUM_PORTS_MASK (0xF << 0)
#define NUM_PORTS_SHIFT (0)
+#define GFX_MPU_SHIFT (12)
#define NUM_MACROS_MASK (0xF << 8)
#define NUM_MACROS_SHIFT (8)
@@ -73,7 +77,7 @@
#define CORE_ON (0x2)
#define PERI_ON (0x1)
#define CLK_OFF (0x4)
-#define MACRO_ON (CORE_ON|PERI_ON)
+#define MACRO_ON (0x0)
#define MACRO_SLEEP_RETENTION (CLK_OFF|CORE_ON)
#define MACRO_SLEEP_RETENTION_PERI_ON (CLK_OFF|MACRO_ON)
#define MACRO_OFF (CLK_OFF)
@@ -166,6 +170,8 @@
else
rc = ocmem_write(new_state,
ocmem_base + PSCGC_CTL_n(region_num));
+ /* Barrier to commit the region state */
+ mb();
return 0;
}
@@ -325,6 +331,9 @@
/* In narrow mode each macro is allowed to be in a different state */
/* The region mode is simply the collection of all macro states */
for (i = 0; i < region->num_macros; i++) {
+ pr_debug("aggregated region state %x\n", r_state);
+ pr_debug("macro %d\n state %x\n", i,
+ region->macro[i].m_state);
r_state &= ~M_PSCGC_CTL_n(i);
r_state |= region->macro[i].m_state << (i * 4);
}
@@ -384,6 +393,198 @@
return 0;
}
+
+static int switch_region_mode(unsigned long offset, unsigned long len,
+ enum region_mode new_mode)
+{
+ unsigned region_start = num_regions;
+ unsigned region_end = num_regions;
+ int i = 0;
+
+ if (offset < 0)
+ return -EINVAL;
+
+ if (len < region_size)
+ return -EINVAL;
+
+ pr_debug("ocmem: mode_transistion to %x\n", new_mode);
+
+ region_start = offset / region_size;
+ region_end = (offset + len - 1) / region_size;
+
+ pr_debug("ocmem: region start %u end %u\n", region_start, region_end);
+
+ if (region_start >= num_regions ||
+ (region_end >= num_regions))
+ return -EINVAL;
+
+ for (i = region_start; i <= region_end; i++) {
+ struct ocmem_hw_region *region = ®ion_ctrl[i];
+ if (region->mode == MODE_DEFAULT) {
+ /* No prior mode programming on this region */
+ /* Set the region to its new mode */
+ region->mode = new_mode;
+ atomic_inc(®ion->mode_counter);
+ pr_debug("Region (%d) switching to mode %d\n",
+ i, new_mode);
+ continue;
+ } else if (region->mode != new_mode) {
+ /* The region is currently set to a different mode */
+ if (new_mode == MODE_DEFAULT) {
+ if (atomic_dec_and_test
+ (®ion->mode_counter)) {
+ region->mode = MODE_DEFAULT;
+ pr_debug("Region (%d) restoring to default mode\n",
+ i);
+ } else {
+ /* More than 1 client in region */
+ /* Cannot move to default mode */
+ pr_debug("Region (%d) using current mode %d\n",
+ i, region->mode);
+ continue;
+ }
+ } else {
+ /* Do not switch modes */
+ pr_err("Region (%d) requested mode %x conflicts with current\n",
+ i, new_mode);
+ goto mode_switch_fail;
+ }
+ }
+ }
+ return 0;
+
+mode_switch_fail:
+ return -EINVAL;
+}
+
+#ifdef CONFIG_MSM_OCMEM_NONSECURE
+
+static int commit_region_modes(void)
+{
+ uint32_t region_mode_ctrl = 0x0;
+ unsigned pos = 0;
+ unsigned i = 0;
+
+ for (i = 0; i < num_regions; i++) {
+ struct ocmem_hw_region *region = ®ion_ctrl[i];
+ pos = i << 2;
+ if (region->mode == THIN_MODE)
+ region_mode_ctrl |= BIT(pos);
+ }
+ pr_debug("ocmem_region_mode_control %x\n", region_mode_ctrl);
+ ocmem_write(region_mode_ctrl, ocmem_base + OC_REGION_MODE_CTL);
+ /* Barrier to commit the region mode */
+ mb();
+ return 0;
+}
+
+static int ocmem_gfx_mpu_set(unsigned long offset, unsigned long len)
+{
+ int mpu_start = 0x0;
+ int mpu_end = 0x0;
+
+ if (offset)
+ mpu_start = (offset >> GFX_MPU_SHIFT) - 1;
+ if (mpu_start < 0)
+ /* Avoid underflow */
+ mpu_start = 0;
+ mpu_end = ((offset+len) >> GFX_MPU_SHIFT) - 1;
+ BUG_ON(mpu_end < 0);
+
+ pr_debug("ocmem: mpu: start %x end %x\n", mpu_start, mpu_end);
+ ocmem_write(mpu_start << GFX_MPU_SHIFT, ocmem_base + OC_GFX_MPU_START);
+ ocmem_write(mpu_end << GFX_MPU_SHIFT, ocmem_base + OC_GFX_MPU_END);
+ return 0;
+}
+
+static void ocmem_gfx_mpu_remove(void)
+{
+ ocmem_write(0x0, ocmem_base + OC_GFX_MPU_START);
+ ocmem_write(0x0, ocmem_base + OC_GFX_MPU_END);
+}
+
+static int do_lock(enum ocmem_client id, unsigned long offset,
+ unsigned long len, enum region_mode mode)
+{
+ return 0;
+}
+
+static int do_unlock(enum ocmem_client id, unsigned long offset,
+ unsigned long len)
+{
+ ocmem_clear(offset, len);
+ return 0;
+}
+#else
+static int ocmem_gfx_mpu_set(unsigned long offset, unsigned long len)
+{
+ return 0;
+}
+
+static void ocmem_gfx_mpu_remove(void)
+{
+}
+
+static int commit_region_modes(void)
+{
+ return 0;
+}
+
+static int do_lock(enum ocmem_client id, unsigned long offset,
+ unsigned long len, enum region_mode mode)
+{
+ return 0;
+}
+
+static int do_unlock(enum ocmem_client id, unsigned long offset,
+ unsigned long len)
+{
+ return 0;
+}
+#endif /* CONFIG_MSM_OCMEM_NONSECURE */
+
+int ocmem_lock(enum ocmem_client id, unsigned long offset, unsigned long len,
+ enum region_mode mode)
+{
+
+ if (len < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: Invalid len %lx for lock\n", len);
+ return -EINVAL;
+ }
+
+ if (id == OCMEM_GRAPHICS)
+ ocmem_gfx_mpu_set(offset, len);
+
+ mutex_lock(®ion_ctrl_lock);
+
+ if (switch_region_mode(offset, len, mode) < 0)
+ goto switch_region_fail;
+
+ commit_region_modes();
+
+ do_lock(id, offset, len, mode);
+
+ mutex_unlock(®ion_ctrl_lock);
+ return 0;
+
+switch_region_fail:
+ mutex_unlock(®ion_ctrl_lock);
+ return -EINVAL;
+}
+
+int ocmem_unlock(enum ocmem_client id, unsigned long offset, unsigned long len)
+{
+ if (id == OCMEM_GRAPHICS)
+ ocmem_gfx_mpu_remove();
+
+ mutex_lock(®ion_ctrl_lock);
+ do_unlock(id, offset, len);
+ switch_region_mode(offset, len , MODE_DEFAULT);
+ commit_region_modes();
+ mutex_unlock(®ion_ctrl_lock);
+ return 0;
+}
+
#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
static int ocmem_core_set_default_state(void)
{
@@ -398,6 +599,9 @@
if (rc < 0)
return rc;
+ rc = ocmem_enable_br_clock();
+ if (rc < 0)
+ return rc;
return 0;
}
@@ -808,6 +1012,7 @@
struct msm_rpm_request *req = NULL;
region->interleaved = interleaved;
region->mode = MODE_DEFAULT;
+ atomic_set(®ion->mode_counter, 0);
region->r_state = REGION_DEFAULT_OFF;
region->num_macros = num_banks;
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index ccbef9b..85dc85d 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -38,8 +38,12 @@
#define DM_INTR_CLR (0x8)
#define DM_INTR_MASK (0xC)
-#define DM_GEN_STATUS (0x10)
-#define DM_STATUS (0x14)
+#define DM_INT_STATUS (0x10)
+#define DM_GEN_STATUS (0x14)
+#define DM_CLR_OFFSET (0x18)
+#define DM_CLR_SIZE (0x1C)
+#define DM_CLR_PATTERN (0x20)
+#define DM_CLR_TRIGGER (0x24)
#define DM_CTRL (0x1000)
#define DM_TBL_BASE (0x1010)
#define DM_TBL_IDX(x) ((x) * 0x18)
@@ -82,8 +86,9 @@
#define DM_DIR_SHIFT 0x0
#define DM_DONE 0x1
-#define DM_INTR_ENABLE 0x0
-#define DM_INTR_DISABLE 0x1
+#define DM_MASK_RESET 0x0
+#define DM_INTR_RESET 0x20003
+#define DM_CLR_ENABLE 0x1
static void *br_base;
static void *dm_base;
@@ -122,12 +127,59 @@
static irqreturn_t ocmem_dm_irq_handler(int irq, void *dev_id)
{
+ unsigned status;
+ unsigned irq_status;
+ status = ocmem_read(dm_base + DM_GEN_STATUS);
+ irq_status = ocmem_read(dm_base + DM_INT_STATUS);
+ pr_debug("irq:dm_status %x irq_status %x\n", status, irq_status);
+ if (irq_status & BIT(0)) {
+ pr_debug("Data mover completed\n");
+ irq_status &= ~BIT(0);
+ ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ } else if (irq_status & BIT(1)) {
+ pr_debug("Data clear engine completed\n");
+ irq_status &= ~BIT(1);
+ ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ } else {
+ BUG_ON(1);
+ }
atomic_set(&dm_pending, 0);
- ocmem_write(DM_INTR_DISABLE, dm_base + DM_INTR_CLR);
wake_up_interruptible(&dm_wq);
return IRQ_HANDLED;
}
+#ifdef CONFIG_MSM_OCMEM_NONSECURE
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+ atomic_set(&dm_pending, 1);
+ /* Clear DM Mask */
+ ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
+ /* Clear DM Interrupts */
+ ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
+ /* DM CLR offset */
+ ocmem_write(start, dm_base + DM_CLR_OFFSET);
+ /* DM CLR size */
+ ocmem_write(size, dm_base + DM_CLR_SIZE);
+ /* Wipe out memory as "OCMM" */
+ ocmem_write(0x4D4D434F, dm_base + DM_CLR_PATTERN);
+ /* The offset, size and pattern for clearing must be set
+ * before triggering the clearing engine
+ */
+ mb();
+ /* Trigger Data Clear */
+ ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
+
+ wait_event_interruptible(dm_wq,
+ atomic_read(&dm_pending) == 0);
+ return 0;
+}
+#else
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+ return 0;
+}
+#endif
+
/* Lock during transfers */
int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
unsigned long start, int direction)
@@ -195,9 +247,13 @@
dm_ctrl |= (DM_BLOCK_256 << DM_BR_BLK_SHIFT);
dm_ctrl |= (direction << DM_DIR_SHIFT);
- status = ocmem_read(dm_base + DM_STATUS);
+ status = ocmem_read(dm_base + DM_GEN_STATUS);
pr_debug("Transfer status before %x\n", status);
atomic_set(&dm_pending, 1);
+ /* The DM and BR tables must be programmed before triggering the
+ * Data Mover else the coherent transfer would be corrupted
+ */
+ mb();
/* Trigger DM */
ocmem_write(dm_ctrl, dm_base + DM_CTRL);
pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
@@ -236,8 +292,10 @@
}
init_waitqueue_head(&dm_wq);
+ /* Clear DM Mask */
+ ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
/* enable dm interrupts */
- ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+ ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
ocmem_disable_core_clock();
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index c95728e..e8854d5 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -202,6 +202,15 @@
return 0;
}
+inline int get_mode(int id)
+{
+ if (!check_id(id))
+ return MODE_NOT_SET;
+ else
+ return ocmem_client_table[id].mode == OCMEM_PERFORMANCE ?
+ WIDE_MODE : THIN_MODE;
+}
+
/* Returns the address that can be used by a device core to access OCMEM */
static unsigned long device_address(int id, unsigned long addr)
{
@@ -577,11 +586,38 @@
rc = ocmem_enable_iface_clock();
if (rc < 0)
+ goto iface_clock_fail;
+
+ rc = ocmem_enable_br_clock();
+
+ if (rc < 0)
+ goto br_clock_fail;
+
+ rc = do_map(req);
+
+ if (rc < 0) {
+ pr_err("ocmem: Failed to map request %p for %d\n",
+ req, req->owner);
goto process_map_fail;
- return do_map(req);
+ }
+ if (ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
+ get_mode(req->owner))) {
+ pr_err("ocmem: Failed to secure request %p for %d\n", req,
+ req->owner);
+ rc = -EINVAL;
+ goto lock_failed;
+ }
+
+ return 0;
+lock_failed:
+ do_unmap(req);
process_map_fail:
+ ocmem_disable_br_clock();
+br_clock_fail:
+ ocmem_disable_iface_clock();
+iface_clock_fail:
ocmem_disable_core_clock();
core_clock_fail:
pr_err("ocmem: Failed to map ocmem request\n");
@@ -593,16 +629,25 @@
{
int rc = 0;
+ if (ocmem_unlock(req->owner, phys_to_offset(req->req_start),
+ req->req_sz)) {
+ pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
+ req->owner);
+ rc = -EINVAL;
+ goto unlock_failed;
+ }
+
rc = do_unmap(req);
if (rc < 0)
goto process_unmap_fail;
+ ocmem_disable_br_clock();
ocmem_disable_iface_clock();
ocmem_disable_core_clock();
-
return 0;
+unlock_failed:
process_unmap_fail:
pr_err("ocmem: Failed to unmap ocmem request\n");
return rc;
@@ -1306,7 +1351,6 @@
return -EINVAL;
}
-
if (req->req_sz != 0) {
offset = phys_to_offset(req->req_start);
@@ -1321,7 +1365,6 @@
}
rc = do_free(req);
-
if (rc < 0)
return -EINVAL;
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 11f6b28..6189da8 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -720,11 +720,22 @@
mutex_lock(&module->lock);
switch (event) {
case RPC_ADSP_RTOS_MOD_READY:
- MM_INFO("module %s: READY\n", module->name);
- module->state = ADSP_STATE_ENABLED;
- wake_up(&module->state_wait);
- adsp_set_image(module->info, image);
- break;
+ if (module->state == ADSP_STATE_ENABLING) {
+ MM_INFO("module %s: READY\n", module->name);
+ module->state = ADSP_STATE_ENABLED;
+ wake_up(&module->state_wait);
+ adsp_set_image(module->info, image);
+ break;
+ } else {
+ MM_ERR("module %s got READY event in state[%d]\n",
+ module->name,
+ module->state);
+ rpc_send_accepted_void_reply(rpc_cb_server_client,
+ req->xid,
+ RPC_ACCEPTSTAT_GARBAGE_ARGS);
+ mutex_unlock(&module->lock);
+ return;
+ }
case RPC_ADSP_RTOS_MOD_DISABLE:
MM_INFO("module %s: DISABLED\n", module->name);
module->state = ADSP_STATE_DISABLED;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 1937aafc..20cc724 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -21,7 +21,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include <linux/debugfs.h>
#include "audio_utils_aio.h"
@@ -93,39 +93,6 @@
sizeof(meta_data->meta_out_dsp[0]);
}
-void extract_meta_out_info(struct q6audio_aio *audio,
- struct audio_aio_buffer_node *buf_node, int dir)
-{
- struct dec_meta_out *meta_data = buf_node->kvaddr;
- if (dir) { /* input buffer - Write */
- if (audio->buf_cfg.meta_info_enable)
- memcpy(&buf_node->meta_info.meta_in,
- (char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
- else
- memset(&buf_node->meta_info.meta_in,
- 0, sizeof(struct dec_meta_in));
- pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
- __func__, audio,
- buf_node->meta_info.meta_in.ntimestamp.highpart,
- buf_node->meta_info.meta_in.ntimestamp.lowpart,
- buf_node->meta_info.meta_in.nflags);
- } else { /* output buffer - Read */
- memcpy((char *)buf_node->kvaddr,
- &buf_node->meta_info.meta_out,
- sizeof(struct dec_meta_out));
- meta_data->meta_out_dsp[0].nflags = 0x00000000;
- pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
- __func__, audio,
- ((struct dec_meta_out *)buf_node->kvaddr)->\
- meta_out_dsp[0].msw_ts,
- ((struct dec_meta_out *)buf_node->kvaddr)->\
- meta_out_dsp[0].lsw_ts,
- ((struct dec_meta_out *)buf_node->kvaddr)->\
- meta_out_dsp[0].nflags,
- ((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
- }
-}
-
static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
unsigned long len,
struct audio_aio_ion_region **region)
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
index 8304cb8..b46e0d3 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils_aio.h"
@@ -121,6 +121,39 @@
}
}
+void extract_meta_out_info(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node, int dir)
+{
+ struct dec_meta_out *meta_data = buf_node->kvaddr;
+ if (dir) { /* input buffer - Write */
+ if (audio->buf_cfg.meta_info_enable)
+ memcpy(&buf_node->meta_info.meta_in,
+ (char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
+ else
+ memset(&buf_node->meta_info.meta_in,
+ 0, sizeof(struct dec_meta_in));
+ pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+ __func__, audio,
+ buf_node->meta_info.meta_in.ntimestamp.highpart,
+ buf_node->meta_info.meta_in.ntimestamp.lowpart,
+ buf_node->meta_info.meta_in.nflags);
+ } else { /* output buffer - Read */
+ memcpy((char *)buf_node->kvaddr,
+ &buf_node->meta_info.meta_out,
+ sizeof(struct dec_meta_out));
+ meta_data->meta_out_dsp[0].nflags = 0x00000000;
+ pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
+ __func__, audio,
+ ((struct dec_meta_out *)buf_node->kvaddr)->\
+ meta_out_dsp[0].msw_ts,
+ ((struct dec_meta_out *)buf_node->kvaddr)->\
+ meta_out_dsp[0].lsw_ts,
+ ((struct dec_meta_out *)buf_node->kvaddr)->\
+ meta_out_dsp[0].nflags,
+ ((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+ }
+}
+
/* Read buffer from DSP / Handle Ack from DSP */
void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
uint32_t *payload)
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
index ad4fc6f..10adc26 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/ioctls.h>
#include "audio_utils_aio.h"
@@ -110,6 +110,46 @@
}
}
+void extract_meta_out_info(struct q6audio_aio *audio,
+ struct audio_aio_buffer_node *buf_node, int dir)
+{
+ struct dec_meta_out *meta_data = buf_node->kvaddr;
+ uint32_t temp;
+
+ if (dir) { /* input buffer - Write */
+ if (audio->buf_cfg.meta_info_enable)
+ memcpy(&buf_node->meta_info.meta_in,
+ (char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
+ else
+ memset(&buf_node->meta_info.meta_in,
+ 0, sizeof(struct dec_meta_in));
+ pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+ __func__, audio,
+ buf_node->meta_info.meta_in.ntimestamp.highpart,
+ buf_node->meta_info.meta_in.ntimestamp.lowpart,
+ buf_node->meta_info.meta_in.nflags);
+ } else { /* output buffer - Read */
+ memcpy((char *)buf_node->kvaddr,
+ &buf_node->meta_info.meta_out,
+ sizeof(struct dec_meta_out));
+ meta_data->meta_out_dsp[0].nflags = 0x00000000;
+ temp = meta_data->meta_out_dsp[0].msw_ts;
+ meta_data->meta_out_dsp[0].msw_ts =
+ meta_data->meta_out_dsp[0].lsw_ts;
+ meta_data->meta_out_dsp[0].lsw_ts = temp;
+
+ pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
+ __func__, audio,
+ ((struct dec_meta_out *)buf_node->kvaddr)->\
+ meta_out_dsp[0].msw_ts,
+ ((struct dec_meta_out *)buf_node->kvaddr)->\
+ meta_out_dsp[0].lsw_ts,
+ ((struct dec_meta_out *)buf_node->kvaddr)->\
+ meta_out_dsp[0].nflags,
+ ((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+ }
+}
+
/* Read buffer from DSP / Handle Ack from DSP */
void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
uint32_t *payload)
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index e75d730..8fe3571 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -74,6 +74,11 @@
VOLTAGE_RANGE( 750000, 1537500, 12500),
};
+static struct vreg_range ln_ldo_ranges[] = {
+ VOLTAGE_RANGE( 690000, 1110000, 60000),
+ VOLTAGE_RANGE(1380000, 2220000, 120000),
+};
+
static struct vreg_range smps_ranges[] = {
VOLTAGE_RANGE( 375000, 737500, 12500),
VOLTAGE_RANGE( 750000, 1487500, 12500),
@@ -93,6 +98,7 @@
static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
+static struct vreg_set_points ln_ldo_set_points = SET_POINTS(ln_ldo_ranges);
static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
@@ -101,6 +107,7 @@
&pldo_set_points,
&nldo_set_points,
&nldo1200_set_points,
+ &ln_ldo_set_points,
&smps_set_points,
&ftsmps_set_points,
&ncp_set_points,
@@ -190,6 +197,7 @@
LDO(L10, "8921_l10", "8921_l10_pc", pldo, LDO_600, 0),
LDO(L11, "8921_l11", "8921_l11_pc", pldo, LDO_150, 0),
LDO(L12, "8921_l12", "8921_l12_pc", nldo, LDO_150, 1),
+ LDO(L13, "8921_l13", NULL, ln_ldo, LDO_5, 0),
LDO(L14, "8921_l14", "8921_l14_pc", pldo, LDO_50, 0),
LDO(L15, "8921_l15", "8921_l15_pc", pldo, LDO_150, 0),
LDO(L16, "8921_l16", "8921_l16_pc", pldo, LDO_300, 0),
@@ -264,8 +272,12 @@
{
int real_id;
- if (id >= RPM_VREG_ID_PM8921_L1_PC && id <= RPM_VREG_ID_PM8921_L23_PC)
+ if (id >= RPM_VREG_ID_PM8921_L1_PC && id <= RPM_VREG_ID_PM8921_L12_PC)
real_id = id - RPM_VREG_ID_PM8921_L1_PC;
+ else if (id >= RPM_VREG_ID_PM8921_L14_PC
+ && id <= RPM_VREG_ID_PM8921_L23_PC)
+ real_id = id - RPM_VREG_ID_PM8921_L14_PC
+ + RPM_VREG_ID_PM8921_L14;
else if (id >= RPM_VREG_ID_PM8921_L29_PC
&& id <= RPM_VREG_ID_PM8921_S4_PC)
real_id = id - RPM_VREG_ID_PM8921_L29_PC
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index cd5556a..b112c90 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -490,13 +490,14 @@
pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
+ if (!pkt_sz)
+ return -EAGAIN;
+
BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
return -EAGAIN;
- BUG_ON(pkt_sz == 0);
-
do {
int len;
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 7818c49..cc3b956 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -27,6 +27,9 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/debugfs.h>
#include <asm/current.h>
@@ -52,9 +55,18 @@
struct list_head list;
};
+enum subsys_state {
+ SUBSYS_OFFLINE,
+ SUBSYS_ONLINE,
+};
+
+static const char * const subsys_states[] = {
+ [SUBSYS_OFFLINE] = "OFFLINE",
+ [SUBSYS_ONLINE] = "ONLINE",
+};
+
struct subsys_device {
struct subsys_desc *desc;
- struct list_head list;
struct wake_lock wake_lock;
char wlname[64];
struct work_struct work;
@@ -62,21 +74,58 @@
int restart_count;
void *notify;
+ struct device dev;
+ struct module *owner;
+ int count;
+ enum subsys_state state;
+ int id;
struct mutex shutdown_lock;
struct mutex powerup_lock;
void *restart_order;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
};
+static struct subsys_device *to_subsys(struct device *d)
+{
+ return container_of(d, struct subsys_device, dev);
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->desc->name);
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ enum subsys_state state = to_subsys(dev)->state;
+ return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
+}
+
+static struct device_attribute subsys_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(state),
+ __ATTR_NULL,
+};
+
+static struct bus_type subsys_bus_type = {
+ .name = "msm_subsys",
+ .dev_attrs = subsys_attrs,
+};
+
+static DEFINE_IDA(subsys_ida);
+
static int enable_ramdumps;
module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
struct workqueue_struct *ssr_wq;
static LIST_HEAD(restart_log_list);
-static LIST_HEAD(subsystem_list);
-static DEFINE_MUTEX(subsystem_list_lock);
static DEFINE_MUTEX(soc_order_reg_lock);
static DEFINE_MUTEX(restart_log_mutex);
@@ -101,28 +150,16 @@
static const char * const _order_8x60_modems[] = {"external_modem", "modem"};
DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems);
-/* MSM 8960 restart ordering info */
-static const char * const order_8960[] = {"modem", "lpass"};
/*SGLTE restart ordering info*/
static const char * const order_8960_sglte[] = {"external_modem",
"modem"};
-static struct subsys_soc_restart_order restart_orders_8960_one = {
- .subsystem_list = order_8960,
- .count = ARRAY_SIZE(order_8960),
- .subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL}
- };
-
static struct subsys_soc_restart_order restart_orders_8960_fusion_sglte = {
.subsystem_list = order_8960_sglte,
.count = ARRAY_SIZE(order_8960_sglte),
.subsys_ptrs = {[ARRAY_SIZE(order_8960_sglte)] = NULL}
};
-static struct subsys_soc_restart_order *restart_orders_8960[] = {
- &restart_orders_8960_one,
- };
-
static struct subsys_soc_restart_order *restart_orders_8960_sglte[] = {
&restart_orders_8960_fusion_sglte,
};
@@ -156,9 +193,13 @@
return ret;
switch (restart_level) {
- case RESET_SOC:
- case RESET_SUBSYS_COUPLED:
case RESET_SUBSYS_INDEPENDENT:
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+ pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
+ restart_level = RESET_SUBSYS_COUPLED;
+ }
+ case RESET_SUBSYS_COUPLED:
+ case RESET_SOC:
pr_info("Phase %d behavior activated.\n", restart_level);
break;
default:
@@ -312,6 +353,24 @@
panic("[%p]: Failed to powerup %s!", current, name);
}
+static int __find_subsys(struct device *dev, void *data)
+{
+ struct subsys_device *subsys = to_subsys(dev);
+ return !strcmp(subsys->desc->name, data);
+}
+
+static struct subsys_device *find_subsys(const char *str)
+{
+ struct device *dev;
+
+ if (!str)
+ return NULL;
+
+ dev = bus_find_device(&subsys_bus_type, NULL, (void *)str,
+ __find_subsys);
+ return dev ? to_subsys(dev) : NULL;
+}
+
static void subsystem_restart_wq_func(struct work_struct *work)
{
struct subsys_device *dev = container_of(work,
@@ -436,8 +495,17 @@
int subsystem_restart_dev(struct subsys_device *dev)
{
- const char *name = dev->desc->name;
+ const char *name;
+ if (!get_device(&dev->dev))
+ return -ENODEV;
+
+ if (!try_module_get(dev->owner)) {
+ put_device(&dev->dev);
+ return -ENODEV;
+ }
+
+ name = dev->desc->name;
pr_info("Restart sequence requested for %s, restart_level = %d.\n",
name, restart_level);
@@ -454,6 +522,8 @@
panic("subsys-restart: Unknown restart level!\n");
break;
}
+ module_put(dev->owner);
+ put_device(&dev->dev);
return 0;
}
@@ -461,69 +531,192 @@
int subsystem_restart(const char *name)
{
- struct subsys_device *dev;
+ int ret;
+ struct subsys_device *dev = find_subsys(name);
- mutex_lock(&subsystem_list_lock);
- list_for_each_entry(dev, &subsystem_list, list)
- if (!strncmp(dev->desc->name, name, SUBSYS_NAME_MAX_LENGTH))
- goto found;
- dev = NULL;
-found:
- mutex_unlock(&subsystem_list_lock);
- if (dev)
- return subsystem_restart_dev(dev);
- return -ENODEV;
+ if (!dev)
+ return -ENODEV;
+
+ ret = subsystem_restart_dev(dev);
+ put_device(&dev->dev);
+ return ret;
}
EXPORT_SYMBOL(subsystem_restart);
+#ifdef CONFIG_DEBUG_FS
+static ssize_t subsys_debugfs_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ int r;
+ char buf[40];
+ struct subsys_device *subsys = filp->private_data;
+
+ r = snprintf(buf, sizeof(buf), "%d\n", subsys->count);
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t subsys_debugfs_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ struct subsys_device *subsys = filp->private_data;
+ char buf[10];
+ char *cmp;
+
+ cnt = min(cnt, sizeof(buf) - 1);
+ if (copy_from_user(&buf, ubuf, cnt))
+ return -EFAULT;
+ buf[cnt] = '\0';
+ cmp = strstrip(buf);
+
+ if (!strcmp(cmp, "restart")) {
+ if (subsystem_restart_dev(subsys))
+ return -EIO;
+ } else {
+ return -EINVAL;
+ }
+
+ return cnt;
+}
+
+static const struct file_operations subsys_debugfs_fops = {
+ .open = simple_open,
+ .read = subsys_debugfs_read,
+ .write = subsys_debugfs_write,
+};
+
+static struct dentry *subsys_base_dir;
+
+static int __init subsys_debugfs_init(void)
+{
+ subsys_base_dir = debugfs_create_dir("msm_subsys", NULL);
+ return !subsys_base_dir ? -ENOMEM : 0;
+}
+
+static void subsys_debugfs_exit(void)
+{
+ debugfs_remove_recursive(subsys_base_dir);
+}
+
+static int subsys_debugfs_add(struct subsys_device *subsys)
+{
+ if (!subsys_base_dir)
+ return -ENOMEM;
+
+ subsys->dentry = debugfs_create_file(subsys->desc->name,
+ S_IRUGO | S_IWUSR, subsys_base_dir,
+ subsys, &subsys_debugfs_fops);
+ return !subsys->dentry ? -ENOMEM : 0;
+}
+
+static void subsys_debugfs_remove(struct subsys_device *subsys)
+{
+ debugfs_remove(subsys->dentry);
+}
+#else
+static int __init subsys_debugfs_init(void) { return 0; };
+static void subsys_debugfs_exit(void) { }
+static int subsys_debugfs_add(struct subsys_device *subsys) { return 0; }
+static void subsys_debugfs_remove(struct subsys_device *subsys) { }
+#endif
+
+static void subsys_device_release(struct device *dev)
+{
+ struct subsys_device *subsys = to_subsys(dev);
+
+ wake_lock_destroy(&subsys->wake_lock);
+ mutex_destroy(&subsys->shutdown_lock);
+ mutex_destroy(&subsys->powerup_lock);
+ ida_simple_remove(&subsys_ida, subsys->id);
+ kfree(subsys);
+}
+
struct subsys_device *subsys_register(struct subsys_desc *desc)
{
- struct subsys_device *dev;
+ struct subsys_device *subsys;
+ int ret;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
+ subsys = kzalloc(sizeof(*subsys), GFP_KERNEL);
+ if (!subsys)
return ERR_PTR(-ENOMEM);
- dev->desc = desc;
- dev->notify = subsys_notif_add_subsys(desc->name);
- dev->restart_order = update_restart_order(dev);
+ subsys->desc = desc;
+ subsys->owner = desc->owner;
+ subsys->dev.parent = desc->dev;
+ subsys->dev.bus = &subsys_bus_type;
+ subsys->dev.release = subsys_device_release;
- snprintf(dev->wlname, sizeof(dev->wlname), "ssr(%s)", desc->name);
- wake_lock_init(&dev->wake_lock, WAKE_LOCK_SUSPEND, dev->wlname);
- INIT_WORK(&dev->work, subsystem_restart_wq_func);
- spin_lock_init(&dev->restart_lock);
+ subsys->notify = subsys_notif_add_subsys(desc->name);
+ subsys->restart_order = update_restart_order(subsys);
- mutex_init(&dev->shutdown_lock);
- mutex_init(&dev->powerup_lock);
+ snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name);
+ wake_lock_init(&subsys->wake_lock, WAKE_LOCK_SUSPEND, subsys->wlname);
+ INIT_WORK(&subsys->work, subsystem_restart_wq_func);
+ spin_lock_init(&subsys->restart_lock);
- mutex_lock(&subsystem_list_lock);
- list_add(&dev->list, &subsystem_list);
- mutex_unlock(&subsystem_list_lock);
+ subsys->id = ida_simple_get(&subsys_ida, 0, 0, GFP_KERNEL);
+ if (subsys->id < 0) {
+ ret = subsys->id;
+ goto err_ida;
+ }
+ dev_set_name(&subsys->dev, "subsys%d", subsys->id);
- return dev;
+ mutex_init(&subsys->shutdown_lock);
+ mutex_init(&subsys->powerup_lock);
+
+ ret = subsys_debugfs_add(subsys);
+ if (ret)
+ goto err_debugfs;
+
+ ret = device_register(&subsys->dev);
+ if (ret) {
+ put_device(&subsys->dev);
+ goto err_register;
+ }
+
+ return subsys;
+
+err_register:
+ subsys_debugfs_remove(subsys);
+err_debugfs:
+ mutex_destroy(&subsys->shutdown_lock);
+ mutex_destroy(&subsys->powerup_lock);
+ ida_simple_remove(&subsys_ida, subsys->id);
+err_ida:
+ wake_lock_destroy(&subsys->wake_lock);
+ kfree(subsys);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL(subsys_register);
-void subsys_unregister(struct subsys_device *dev)
+void subsys_unregister(struct subsys_device *subsys)
{
- if (IS_ERR_OR_NULL(dev))
+ if (IS_ERR_OR_NULL(subsys))
return;
- mutex_lock(&subsystem_list_lock);
- list_del(&dev->list);
- mutex_unlock(&subsystem_list_lock);
- wake_lock_destroy(&dev->wake_lock);
- kfree(dev);
+
+ if (get_device(&subsys->dev)) {
+ mutex_lock(&subsys->powerup_lock);
+ WARN_ON(subsys->count);
+ device_unregister(&subsys->dev);
+ mutex_unlock(&subsys->powerup_lock);
+ subsys_debugfs_remove(subsys);
+ put_device(&subsys->dev);
+ }
}
EXPORT_SYMBOL(subsys_unregister);
+static int subsys_panic(struct device *dev, void *data)
+{
+ struct subsys_device *subsys = to_subsys(dev);
+
+ if (subsys->desc->crash_shutdown)
+ subsys->desc->crash_shutdown(subsys->desc);
+ return 0;
+}
+
static int ssr_panic_handler(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct subsys_device *dev;
-
- list_for_each_entry(dev, &subsystem_list, list)
- if (dev->desc->crash_shutdown)
- dev->desc->crash_shutdown(dev->desc);
+ bus_for_each_dev(&subsys_bus_type, NULL, NULL, subsys_panic);
return NOTIFY_DONE;
}
@@ -553,21 +746,14 @@
n_restart_orders = ARRAY_SIZE(orders_8x60_all);
}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
- cpu_is_msm8960ab()) {
- if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
- restart_orders = restart_orders_8960_sglte;
- n_restart_orders =
- ARRAY_SIZE(restart_orders_8960_sglte);
- } else {
- restart_orders = restart_orders_8960;
- n_restart_orders = ARRAY_SIZE(restart_orders_8960);
- }
- for (i = 0; i < n_restart_orders; i++) {
- mutex_init(&restart_orders[i]->powerup_lock);
- mutex_init(&restart_orders[i]->shutdown_lock);
- }
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+ restart_orders = restart_orders_8960_sglte;
+ n_restart_orders = ARRAY_SIZE(restart_orders_8960_sglte);
+ }
+
+ for (i = 0; i < n_restart_orders; i++) {
+ mutex_init(&restart_orders[i]->powerup_lock);
+ mutex_init(&restart_orders[i]->shutdown_lock);
}
if (restart_orders == NULL || n_restart_orders < 1) {
@@ -579,11 +765,29 @@
static int __init subsys_restart_init(void)
{
- ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
- if (!ssr_wq)
- panic("Couldn't allocate workqueue for subsystem restart.\n");
+ int ret;
- return ssr_init_soc_restart_orders();
+ ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
+ BUG_ON(!ssr_wq);
+
+ ret = bus_register(&subsys_bus_type);
+ if (ret)
+ goto err_bus;
+ ret = subsys_debugfs_init();
+ if (ret)
+ goto err_debugfs;
+ ret = ssr_init_soc_restart_orders();
+ if (ret)
+ goto err_soc;
+ return 0;
+
+err_soc:
+ subsys_debugfs_exit();
+err_debugfs:
+ bus_unregister(&subsys_bus_type);
+err_bus:
+ destroy_workqueue(ssr_wq);
+ return ret;
}
arch_initcall(subsys_restart_init);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 4ccd89d..f022a2c 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -66,6 +66,7 @@
struct clk *ce_core_src_clk; /* Handle to CE src clk*/
struct clk *ce_core_clk; /* Handle to CE clk */
struct clk *ce_clk; /* Handle to CE clk */
+ struct clk *ce_bus_clk; /* Handle to CE AXI clk*/
qce_comp_func_ptr_t qce_cb; /* qce callback function pointer */
@@ -760,7 +761,7 @@
{
int i, j, ents;
struct sps_iovec *iovec = pce_dev->ce_sps.in_transfer.iovec;
- uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_NWD;
+ uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD;
printk(KERN_INFO "==============================================\n");
printk(KERN_INFO "CONSUMER (TX/IN/DEST) PIPE DESCRIPTOR\n");
@@ -806,11 +807,11 @@
pce_dev->ce_sps.out_transfer.iovec_count = 0;
}
-static void _qce_set_eot_flag(struct sps_transfer *sps_bam_pipe)
+static void _qce_set_flag(struct sps_transfer *sps_bam_pipe, uint32_t flag)
{
struct sps_iovec *iovec = sps_bam_pipe->iovec +
(sps_bam_pipe->iovec_count - 1);
- iovec->flags |= SPS_IOVEC_FLAG_EOT;
+ iovec->flags |= flag;
}
static void _qce_sps_add_data(uint32_t addr, uint32_t len,
@@ -870,7 +871,7 @@
sps_bam_pipe->iovec_count;
iovec->size = cmdptr->size;
iovec->addr = GET_PHYS_ADDR(cmdptr->cmdlist);
- iovec->flags = SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_NWD | flag;
+ iovec->flags = SPS_IOVEC_FLAG_CMD | flag;
sps_bam_pipe->iovec_count++;
return 0;
@@ -959,7 +960,7 @@
/* Producer pipe will handle this connection */
sps_connect_info->mode = SPS_MODE_SRC;
sps_connect_info->options =
- SPS_O_AUTO_ENABLE | SPS_O_EOT;
+ SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_DESC_DONE;
} else {
/* For CE consumer transfer, source should be
* system memory where as destination should
@@ -1009,6 +1010,9 @@
}
sps_event->mode = SPS_TRIGGER_CALLBACK;
+ if (is_producer)
+ sps_event->options = SPS_O_EOT | SPS_O_DESC_DONE;
+ else
sps_event->options = SPS_O_EOT;
sps_event->xfer_done = NULL;
sps_event->user = (void *)pce_dev;
@@ -1093,6 +1097,7 @@
/* SPS driver wll handle the crypto BAM IRQ */
bam.irq = (u32)pce_dev->ce_sps.bam_irq;
bam.manage = SPS_BAM_MGR_LOCAL;
+ bam.ee = 1;
pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
pr_debug("bam virtual base=0x%x\n", (u32)bam.virt_addr);
@@ -1315,9 +1320,8 @@
unsigned char **pvaddr, enum qce_cipher_mode_enum mode,
bool key_128)
{
- struct sps_command_element *ce_vaddr =
- (struct sps_command_element *)(*pvaddr);
- uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+ struct sps_command_element *ce_vaddr;
+ uint32_t ce_vaddr_start;
struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
struct qce_cmdlist_info *pcl_info = NULL;
int i = 0;
@@ -1329,6 +1333,10 @@
uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
+ *pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+ pdev->ce_sps.ce_burst_size);
+ ce_vaddr = (struct sps_command_element *)(*pvaddr);
+ ce_vaddr_start = (uint32_t)(*pvaddr);
crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
BIT(CRYPTO_MASK_DOUT_INTR) |
BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1480,10 +1488,16 @@
0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, &pcl_info->auth_seg_size);
+ } else {
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
+ 0, &pcl_info->auth_seg_size);
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
+ 0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
0, &pcl_info->auth_seg_size);
-
}
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+ (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK), NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1500,9 +1514,8 @@
bool mode_cbc)
{
- struct sps_command_element *ce_vaddr =
- (struct sps_command_element *)(*pvaddr);
- uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+ struct sps_command_element *ce_vaddr;
+ uint32_t ce_vaddr_start;
struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
struct qce_cmdlist_info *pcl_info = NULL;
int i = 0;
@@ -1513,6 +1526,10 @@
uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
+ *pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+ pdev->ce_sps.ce_burst_size);
+ ce_vaddr = (struct sps_command_element *)(*pvaddr);
+ ce_vaddr_start = (uint32_t)(*pvaddr);
crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
BIT(CRYPTO_MASK_DOUT_INTR) |
BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1613,9 +1630,6 @@
&pcl_info->encr_cntr_iv);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
NULL);
- /* Add 2 dummy to align size to burst-size multiple */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR2_IV2_REG, 0,
- NULL);
}
/* Add dummy to align size to burst-size multiple */
if (!mode_cbc) {
@@ -1623,10 +1637,17 @@
0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, &pcl_info->auth_seg_size);
+ } else {
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
+ 0, &pcl_info->auth_seg_size);
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
+ 0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
0, &pcl_info->auth_seg_size);
-
}
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+ (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
+ NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1642,9 +1663,8 @@
unsigned char **pvaddr, enum qce_hash_alg_enum alg,
bool key_128)
{
- struct sps_command_element *ce_vaddr =
- (struct sps_command_element *)(*pvaddr);
- uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+ struct sps_command_element *ce_vaddr;
+ uint32_t ce_vaddr_start;
struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
struct qce_cmdlist_info *pcl_info = NULL;
int i = 0;
@@ -1655,6 +1675,10 @@
uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
+ *pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+ pdev->ce_sps.ce_burst_size);
+ ce_vaddr_start = (uint32_t)(*pvaddr);
+ ce_vaddr = (struct sps_command_element *)(*pvaddr);
crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
BIT(CRYPTO_MASK_DOUT_INTR) |
BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1678,9 +1702,6 @@
iv_reg = 5;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
crypto_cfg, &pcl_info->crypto_cfg);
- /* 1 dummy write */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
- 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, NULL);
@@ -1696,9 +1717,7 @@
iv_reg = 8;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
crypto_cfg, &pcl_info->crypto_cfg);
- /* 2 dummy writes */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
- 0, NULL);
+ /* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1716,9 +1735,6 @@
iv_reg = 5;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
crypto_cfg, &pcl_info->crypto_cfg);
- /* 1 dummy write */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
- 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, NULL);
break;
@@ -1736,9 +1752,7 @@
iv_reg = 5;
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
crypto_cfg, &pcl_info->crypto_cfg);
- /* 2 dummy writes */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
- 0, NULL);
+ /* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1757,9 +1771,7 @@
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
crypto_cfg, &pcl_info->crypto_cfg);
- /* 2 dummy writes */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
- 0, NULL);
+ /* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1797,9 +1809,7 @@
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
crypto_cfg, &pcl_info->crypto_cfg);
- /* 2 dummy writes */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
- 0, NULL);
+ /* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
@@ -1852,6 +1862,10 @@
(CRYPTO_AUTH_KEY0_REG + i*sizeof(uint32_t)),
0, NULL);
}
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+ (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
+ NULL);
+
if (alg != QCE_AEAD_SHA1_HMAC)
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1866,9 +1880,8 @@
static int _setup_aead_cmdlistptrs(struct qce_device *pdev,
unsigned char **pvaddr, bool key_128)
{
- struct sps_command_element *ce_vaddr =
- (struct sps_command_element *)(*pvaddr);
- uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
+ struct sps_command_element *ce_vaddr;
+ uint32_t ce_vaddr_start;
struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
struct qce_cmdlist_info *pcl_info = NULL;
int i = 0;
@@ -1879,6 +1892,10 @@
uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
+ *pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+ pdev->ce_sps.ce_burst_size);
+ ce_vaddr_start = (uint32_t)(*pvaddr);
+ ce_vaddr = (struct sps_command_element *)(*pvaddr);
crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
BIT(CRYPTO_MASK_DOUT_INTR) |
BIT(CRYPTO_MASK_DIN_INTR) |
@@ -1927,8 +1944,6 @@
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
NULL);
- /* add 1 dummy */
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
&pcl_info->seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG,
@@ -1992,6 +2007,10 @@
(CRYPTO_ENCR_CCM_INT_CNTR0_REG + i * sizeof(uint32_t)),
0, NULL);
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+ (crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
&pcl_info->go_proc);
@@ -2005,12 +2024,14 @@
static int _setup_unlock_pipe_cmdlistptrs(struct qce_device *pdev,
unsigned char **pvaddr)
{
- struct sps_command_element *ce_vaddr =
- (struct sps_command_element *)(*pvaddr);
+ struct sps_command_element *ce_vaddr;
uint32_t ce_vaddr_start = (uint32_t)(*pvaddr);
struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
struct qce_cmdlist_info *pcl_info = NULL;
+ *pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+ pdev->ce_sps.ce_burst_size);
+ ce_vaddr = (struct sps_command_element *)(*pvaddr);
cmdlistptr->unlock_all_pipes.cmdlist = (uint32_t)ce_vaddr;
pcl_info = &(cmdlistptr->unlock_all_pipes);
@@ -2044,7 +2065,7 @@
*/
ce_vaddr =
(struct sps_command_element *) ALIGN(((unsigned int) ce_vaddr),
- 16);
+ pdev->ce_sps.ce_burst_size);
*pvaddr = (unsigned char *) ce_vaddr;
_setup_cipher_aes_cmdlistptrs(pdev, pvaddr, QCE_MODE_CBC, true);
@@ -2084,8 +2105,8 @@
unsigned char *vaddr;
vaddr = pce_dev->coh_vmem;
- vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr), 16);
-
+ vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),
+ pce_dev->ce_sps.ce_burst_size);
/* Allow for 256 descriptor (cmd and data) entries per pipe */
pce_dev->ce_sps.in_transfer.iovec = (struct sps_iovec *)vaddr;
pce_dev->ce_sps.in_transfer.iovec_phys =
@@ -2098,6 +2119,8 @@
vaddr += MAX_BAM_DESCRIPTORS * 8;
qce_setup_cmdlistptrs(pce_dev, &vaddr);
+ vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),
+ pce_dev->ce_sps.ce_burst_size);
pce_dev->ce_sps.result_dump = (uint32_t)vaddr;
pce_dev->ce_sps.result = (struct ce_result_dump_format *)vaddr;
vaddr += 128;
@@ -2242,13 +2265,17 @@
_qce_sps_add_sg_data(pce_dev, areq->src, totallen_in,
&pce_dev->ce_sps.in_transfer);
- _qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.in_transfer,
+ SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
+
_qce_sps_add_sg_data(pce_dev, areq->dst, out_len +
areq->assoclen + hw_pad_out,
&pce_dev->ce_sps.out_transfer);
_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
CRYPTO_RESULT_DUMP_SIZE,
&pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
} else {
_qce_sps_add_sg_data(pce_dev, areq->assoc, areq->assoclen,
&pce_dev->ce_sps.in_transfer);
@@ -2256,7 +2283,8 @@
&pce_dev->ce_sps.in_transfer);
_qce_sps_add_sg_data(pce_dev, areq->src, areq->cryptlen,
&pce_dev->ce_sps.in_transfer);
- _qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.in_transfer,
+ SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
/* Pass through to ignore associated (+iv, if applicable) data*/
_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.ignore_buffer),
@@ -2270,6 +2298,8 @@
_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
CRYPTO_RESULT_DUMP_SIZE, &pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer,
+ SPS_IOVEC_FLAG_INT);
}
rc = _qce_sps_transfer(pce_dev);
if (rc)
@@ -2360,13 +2390,15 @@
&pce_dev->ce_sps.in_transfer);
_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
&pce_dev->ce_sps.in_transfer);
- _qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.in_transfer,
+ SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
_qce_sps_add_sg_data(pce_dev, areq->dst, areq->nbytes,
&pce_dev->ce_sps.out_transfer);
_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
CRYPTO_RESULT_DUMP_SIZE,
&pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
rc = _qce_sps_transfer(pce_dev);
if (rc)
goto bad;
@@ -2429,11 +2461,13 @@
&pce_dev->ce_sps.in_transfer);
_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
&pce_dev->ce_sps.in_transfer);
- _qce_set_eot_flag(&pce_dev->ce_sps.in_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.in_transfer,
+ SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
CRYPTO_RESULT_DUMP_SIZE,
&pce_dev->ce_sps.out_transfer);
+ _qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
rc = _qce_sps_transfer(pce_dev);
if (rc)
goto bad;
@@ -2527,6 +2561,7 @@
struct clk *ce_core_clk;
struct clk *ce_clk;
struct clk *ce_core_src_clk;
+ struct clk *ce_bus_clk;
/* Get CE3 src core clk. */
ce_core_src_clk = clk_get(pce_dev->pdev, "core_clk_src");
@@ -2568,6 +2603,19 @@
}
pce_dev->ce_clk = ce_clk;
+ /* Get CE AXI clk */
+ ce_bus_clk = clk_get(pce_dev->pdev, "bus_clk");
+ if (IS_ERR(ce_bus_clk)) {
+ rc = PTR_ERR(ce_bus_clk);
+ pr_err("Unable to get CE BUS interface clk\n");
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
+ clk_put(pce_dev->ce_core_clk);
+ clk_put(pce_dev->ce_clk);
+ goto err_clk;
+ }
+ pce_dev->ce_bus_clk = ce_bus_clk;
+
/* Enable CE core clk */
rc = clk_prepare_enable(pce_dev->ce_core_clk);
if (rc) {
@@ -2589,6 +2637,18 @@
clk_put(pce_dev->ce_clk);
goto err_clk;
}
+ /* Enable AXI clk */
+ rc = clk_prepare_enable(pce_dev->ce_bus_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE BUS clk\n");
+ clk_disable_unprepare(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
+ clk_put(pce_dev->ce_core_clk);
+ clk_put(pce_dev->ce_clk);
+ clk_put(pce_dev->ce_bus_clk);
+ goto err_clk;
+ }
}
err_clk:
if (rc)
@@ -2680,10 +2740,12 @@
clk_disable_unprepare(pce_dev->ce_clk);
clk_disable_unprepare(pce_dev->ce_core_clk);
+ clk_disable_unprepare(pce_dev->ce_bus_clk);
if (pce_dev->ce_core_src_clk != NULL)
clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_clk);
clk_put(pce_dev->ce_core_clk);
+ clk_put(pce_dev->ce_bus_clk);
qce_sps_exit(pce_dev);
kfree(handle);
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 898109e..1c904ed 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -345,6 +345,7 @@
#define CRYPTO_IRQ_ENABLES_MASK (0xF << CRYPTO_IRQ_ENABLES)
#define CRYPTO_LITTLE_ENDIAN_MODE 9
+#define CRYPTO_LITTLE_ENDIAN_MASK (1 << CRYPTO_LITTLE_ENDIAN_MODE)
#define CRYPTO_PIPE_SET_SELECT 5 /* bit 8-5 */
#define CRYPTO_PIPE_SET_SELECT_MASK (0xF << CRYPTO_PIPE_SET_SELECT)
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 4fe1f01..31bbb1f 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -330,8 +330,6 @@
struct ion_client *client = handle->client;
struct ion_buffer *buffer = handle->buffer;
- mutex_lock(&client->lock);
-
mutex_lock(&buffer->lock);
while (handle->kmap_cnt)
ion_handle_kmap_put(handle);
@@ -339,7 +337,6 @@
if (!RB_EMPTY_NODE(&handle->node))
rb_erase(&handle->node, &client->handles);
- mutex_unlock(&client->lock);
ion_buffer_put(buffer);
kfree(handle);
@@ -514,8 +511,8 @@
WARN(1, "%s: invalid handle passed to free.\n", __func__);
return;
}
- mutex_unlock(&client->lock);
ion_handle_put(handle);
+ mutex_unlock(&client->lock);
}
EXPORT_SYMBOL(ion_free);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 1066b49..7241201 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -25,7 +25,7 @@
#include <linux/rbtree.h>
#include <linux/ashmem.h>
#include <linux/major.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <linux/io.h>
#include <mach/socinfo.h>
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index c122270..f908181 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -26,6 +26,7 @@
#include <linux/spmi.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
+#include <linux/completion.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/platform_device.h>
@@ -33,6 +34,491 @@
#define QPNP_VADC_MIN_ADC_CODE 0x6000
/* Max ADC code represents full-scale range of 1.8V */
#define QPNP_VADC_MAX_ADC_CODE 0xA800
+#define KELVINMIL_DEGMIL 273160
+
+/* Units for temperature below (on x axis) is in 0.1DegC as
+ required by the battery driver. Note the resolution used
+ here to compute the table was done for DegC to milli-volts.
+ In consideration to limit the size of the table for the given
+ temperature range below, the result is linearly interpolated
+ and provided to the battery driver in the units desired for
+ their framework which is 0.1DegC. True resolution of 0.1DegC
+ will result in the below table size to increase by 10 times */
+static const struct qpnp_vadc_map_pt adcmap_btm_threshold[] = {
+ {-300, 1642},
+ {-200, 1544},
+ {-100, 1414},
+ {0, 1260},
+ {10, 1244},
+ {20, 1228},
+ {30, 1212},
+ {40, 1195},
+ {50, 1179},
+ {60, 1162},
+ {70, 1146},
+ {80, 1129},
+ {90, 1113},
+ {100, 1097},
+ {110, 1080},
+ {120, 1064},
+ {130, 1048},
+ {140, 1032},
+ {150, 1016},
+ {160, 1000},
+ {170, 985},
+ {180, 969},
+ {190, 954},
+ {200, 939},
+ {210, 924},
+ {220, 909},
+ {230, 894},
+ {240, 880},
+ {250, 866},
+ {260, 852},
+ {270, 838},
+ {280, 824},
+ {290, 811},
+ {300, 798},
+ {310, 785},
+ {320, 773},
+ {330, 760},
+ {340, 748},
+ {350, 736},
+ {360, 725},
+ {370, 713},
+ {380, 702},
+ {390, 691},
+ {400, 681},
+ {410, 670},
+ {420, 660},
+ {430, 650},
+ {440, 640},
+ {450, 631},
+ {460, 622},
+ {470, 613},
+ {480, 604},
+ {490, 595},
+ {500, 587},
+ {510, 579},
+ {520, 571},
+ {530, 563},
+ {540, 556},
+ {550, 548},
+ {560, 541},
+ {570, 534},
+ {580, 527},
+ {590, 521},
+ {600, 514},
+ {610, 508},
+ {620, 502},
+ {630, 496},
+ {640, 490},
+ {650, 485},
+ {660, 281},
+ {670, 274},
+ {680, 267},
+ {690, 260},
+ {700, 254},
+ {710, 247},
+ {720, 241},
+ {730, 235},
+ {740, 229},
+ {750, 224},
+ {760, 218},
+ {770, 213},
+ {780, 208},
+ {790, 203}
+};
+
+static const struct qpnp_vadc_map_pt adcmap_ntcg_104ef_104fb[] = {
+ {696483, -40960},
+ {649148, -39936},
+ {605368, -38912},
+ {564809, -37888},
+ {527215, -36864},
+ {492322, -35840},
+ {460007, -34816},
+ {429982, -33792},
+ {402099, -32768},
+ {376192, -31744},
+ {352075, -30720},
+ {329714, -29696},
+ {308876, -28672},
+ {289480, -27648},
+ {271417, -26624},
+ {254574, -25600},
+ {238903, -24576},
+ {224276, -23552},
+ {210631, -22528},
+ {197896, -21504},
+ {186007, -20480},
+ {174899, -19456},
+ {164521, -18432},
+ {154818, -17408},
+ {145744, -16384},
+ {137265, -15360},
+ {129307, -14336},
+ {121866, -13312},
+ {114896, -12288},
+ {108365, -11264},
+ {102252, -10240},
+ {96499, -9216},
+ {91111, -8192},
+ {86055, -7168},
+ {81308, -6144},
+ {76857, -5120},
+ {72660, -4096},
+ {68722, -3072},
+ {65020, -2048},
+ {61538, -1024},
+ {58261, 0},
+ {55177, 1024},
+ {52274, 2048},
+ {49538, 3072},
+ {46962, 4096},
+ {44531, 5120},
+ {42243, 6144},
+ {40083, 7168},
+ {38045, 8192},
+ {36122, 9216},
+ {34308, 10240},
+ {32592, 11264},
+ {30972, 12288},
+ {29442, 13312},
+ {27995, 14336},
+ {26624, 15360},
+ {25333, 16384},
+ {24109, 17408},
+ {22951, 18432},
+ {21854, 19456},
+ {20807, 20480},
+ {19831, 21504},
+ {18899, 22528},
+ {18016, 23552},
+ {17178, 24576},
+ {16384, 25600},
+ {15631, 26624},
+ {14916, 27648},
+ {14237, 28672},
+ {13593, 29696},
+ {12976, 30720},
+ {12400, 31744},
+ {11848, 32768},
+ {11324, 33792},
+ {10825, 34816},
+ {10354, 35840},
+ {9900, 36864},
+ {9471, 37888},
+ {9062, 38912},
+ {8674, 39936},
+ {8306, 40960},
+ {7951, 41984},
+ {7616, 43008},
+ {7296, 44032},
+ {6991, 45056},
+ {6701, 46080},
+ {6424, 47104},
+ {6160, 48128},
+ {5908, 49152},
+ {5667, 50176},
+ {5439, 51200},
+ {5219, 52224},
+ {5010, 53248},
+ {4810, 54272},
+ {4619, 55296},
+ {4440, 56320},
+ {4263, 57344},
+ {4097, 58368},
+ {3938, 59392},
+ {3785, 60416},
+ {3637, 61440},
+ {3501, 62464},
+ {3368, 63488},
+ {3240, 64512},
+ {3118, 65536},
+ {2998, 66560},
+ {2889, 67584},
+ {2782, 68608},
+ {2680, 69632},
+ {2581, 70656},
+ {2490, 71680},
+ {2397, 72704},
+ {2310, 73728},
+ {2227, 74752},
+ {2147, 75776},
+ {2064, 76800},
+ {1998, 77824},
+ {1927, 78848},
+ {1860, 79872},
+ {1795, 80896},
+ {1736, 81920},
+ {1673, 82944},
+ {1615, 83968},
+ {1560, 84992},
+ {1507, 86016},
+ {1456, 87040},
+ {1407, 88064},
+ {1360, 89088},
+ {1314, 90112},
+ {1271, 91136},
+ {1228, 92160},
+ {1189, 93184},
+ {1150, 94208},
+ {1112, 95232},
+ {1076, 96256},
+ {1042, 97280},
+ {1008, 98304},
+ {976, 99328},
+ {945, 100352},
+ {915, 101376},
+ {886, 102400},
+ {859, 103424},
+ {832, 104448},
+ {807, 105472},
+ {782, 106496},
+ {756, 107520},
+ {735, 108544},
+ {712, 109568},
+ {691, 110592},
+ {670, 111616},
+ {650, 112640},
+ {631, 113664},
+ {612, 114688},
+ {594, 115712},
+ {577, 116736},
+ {560, 117760},
+ {544, 118784},
+ {528, 119808},
+ {513, 120832},
+ {498, 121856},
+ {483, 122880},
+ {470, 123904},
+ {457, 124928},
+ {444, 125952},
+ {431, 126976},
+ {419, 128000}
+};
+
+static int32_t qpnp_adc_map_linear(const struct qpnp_vadc_map_pt *pts,
+ uint32_t tablesize, int32_t input, int64_t *output)
+{
+ bool descending = 1;
+ uint32_t i = 0;
+
+ if ((pts == NULL) || (output == NULL))
+ return -EINVAL;
+
+ /* Check if table is descending or ascending */
+ if (tablesize > 1) {
+ if (pts[0].x < pts[1].x)
+ descending = 0;
+ }
+
+ while (i < tablesize) {
+ if ((descending == 1) && (pts[i].x < input)) {
+ /* table entry is less than measured
+ value and table is descending, stop */
+ break;
+ } else if ((descending == 0) &&
+ (pts[i].x > input)) {
+ /* table entry is greater than measured
+ value and table is ascending, stop */
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ if (i == 0)
+ *output = pts[0].y;
+ else if (i == tablesize)
+ *output = pts[tablesize-1].y;
+ else {
+ /* result is between search_index and search_index-1 */
+ /* interpolate linearly */
+ *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
+ (input - pts[i-1].x))/
+ (pts[i].x - pts[i-1].x))+
+ pts[i-1].y);
+ }
+
+ return 0;
+}
+
+static int32_t qpnp_adc_map_batt_therm(const struct qpnp_vadc_map_pt *pts,
+ uint32_t tablesize, int32_t input, int64_t *output)
+{
+ bool descending = 1;
+ uint32_t i = 0;
+
+ if ((pts == NULL) || (output == NULL))
+ return -EINVAL;
+
+ /* Check if table is descending or ascending */
+ if (tablesize > 1) {
+ if (pts[0].y < pts[1].y)
+ descending = 0;
+ }
+
+ while (i < tablesize) {
+ if ((descending == 1) && (pts[i].y < input)) {
+ /* table entry is less than measured
+ value and table is descending, stop */
+ break;
+ } else if ((descending == 0) && (pts[i].y > input)) {
+ /* table entry is greater than measured
+ value and table is ascending, stop */
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ if (i == 0) {
+ *output = pts[0].x;
+ } else if (i == tablesize) {
+ *output = pts[tablesize-1].x;
+ } else {
+ /* result is between search_index and search_index-1 */
+ /* interpolate linearly */
+ *output = (((int32_t) ((pts[i].x - pts[i-1].x)*
+ (input - pts[i-1].y))/
+ (pts[i].y - pts[i-1].y))+
+ pts[i-1].x);
+ }
+
+ return 0;
+}
+
+static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties)
+{
+ int64_t adc_voltage = 0;
+ bool negative_offset = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties)
+ return -EINVAL;
+
+ adc_voltage = (adc_code -
+ chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
+ * adc_properties->adc_vdd_reference;
+ if (adc_voltage < 0) {
+ negative_offset = 1;
+ adc_voltage = -adc_voltage;
+ }
+ do_div(adc_voltage,
+ chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
+ if (negative_offset)
+ adc_voltage = -adc_voltage;
+
+ return adc_voltage;
+}
+
+int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t pmic_voltage = 0;
+ bool negative_offset = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ pmic_voltage = (adc_code -
+ chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
+ * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+ if (pmic_voltage < 0) {
+ negative_offset = 1;
+ pmic_voltage = -pmic_voltage;
+ }
+ do_div(pmic_voltage,
+ chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
+ if (negative_offset)
+ pmic_voltage = -pmic_voltage;
+ pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+
+ if (pmic_voltage > 0) {
+ /* 2mV/K */
+ adc_chan_result->measurement = pmic_voltage*
+ chan_properties->offset_gain_denominator;
+
+ do_div(adc_chan_result->measurement,
+ chan_properties->offset_gain_numerator * 2);
+ } else {
+ adc_chan_result->measurement = 0;
+ }
+ /* Change to .001 deg C */
+ adc_chan_result->measurement -= KELVINMIL_DEGMIL;
+ adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
+
+/* Scales the ADC code to 0.001 degrees C using the map
+ * table for the XO thermistor.
+ */
+int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t xo_thm = 0;
+
+ if (!chan_properties || !chan_properties->offset_gain_numerator ||
+ !chan_properties->offset_gain_denominator || !adc_properties
+ || !adc_chan_result)
+ return -EINVAL;
+
+ xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+ xo_thm <<= 4;
+ qpnp_adc_map_linear(adcmap_ntcg_104ef_104fb,
+ ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
+ xo_thm, &adc_chan_result->physical);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
+
+int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_batt_therm(
+ adcmap_btm_threshold,
+ ARRAY_SIZE(adcmap_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
+
+int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t batt_id_voltage = 0;
+
+ batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+ adc_chan_result->physical = batt_id_voltage;
+ adc_chan_result->physical = adc_chan_result->measurement;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
int32_t qpnp_adc_scale_default(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
@@ -203,7 +689,7 @@
"qcom,calibration-type", NULL);
if (!strncmp(calibration_param, "absolute", 8))
calib_type = CALIB_ABSOLUTE;
- else if (!strncmp(calibration_param, "historical", 9))
+ else if (!strncmp(calibration_param, "ratiometric", 11))
calib_type = CALIB_RATIOMETRIC;
else {
pr_err("%s: Invalid calibration property\n", __func__);
@@ -252,6 +738,8 @@
return -ENXIO;
}
+ init_completion(&adc_qpnp->adc_rslt_completion);
+
mutex_init(&adc_qpnp->adc_lock);
return 0;
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index b689255..aa375d7 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -33,6 +33,15 @@
#include <linux/platform_device.h>
/* QPNP IADC register definition */
+#define QPNP_IADC_REVISION1 0x0
+#define QPNP_IADC_REVISION2 0x1
+#define QPNP_IADC_REVISION3 0x2
+#define QPNP_IADC_REVISION4 0x3
+#define QPNP_IADC_PERPH_TYPE 0x4
+#define QPNP_IADC_PERH_SUBTYPE 0x5
+
+#define QPNP_IADC_SUPPORTED_REVISION2 1
+
#define QPNP_STATUS1 0x8
#define QPNP_STATUS1_OP_MODE 4
#define QPNP_STATUS1_MULTI_MEAS_EN BIT(3)
@@ -67,13 +76,14 @@
#define QPNP_INT_CLR_FIFO_NOT_EMPTY_INT_EN BIT(1)
#define QPNP_INT_CLR_EOC_INT_EN_CLR BIT(0)
#define QPNP_INT_CLR_MASK 0x1f
-#define QPNP_MODE_CTL 0x40
+#define QPNP_IADC_MODE_CTL 0x40
#define QPNP_OP_MODE_SHIFT 4
#define QPNP_USE_BMS_DATA BIT(4)
#define QPNP_VADC_SYNCH_EN BIT(2)
#define QPNP_OFFSET_RMV_EN BIT(1)
#define QPNP_ADC_TRIM_EN BIT(0)
-#define QPNP_EN_CTL1 0x46
+#define QPNP_IADC_EN_CTL1 0x46
+#define QPNP_IADC_ADC_EN BIT(7)
#define QPNP_ADC_CH_SEL_CTL 0x48
#define QPNP_ADC_DIG_PARAM 0x50
#define QPNP_ADC_CLK_SEL_MASK 0x3
@@ -101,13 +111,6 @@
#define QPNP_DATA1 0x61
#define QPNP_CONV_TIMEOUT_ERR 2
-#define QPNP_IADC_MODE_CTL 0x40
-#define QPNP_IADC_USE_BMS_DATA BIT(4)
-#define QPNP_IADC_RESERVED_BIT3 BIT(3)
-#define QPNP_IADC_VADC_SYNC_EN BIT(2)
-#define QPNP_IADC_OFFSET_RMV_EN BIT(1)
-#define QPNP_IADC_ADC_TRIM_EN BIT(0)
-
#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
@@ -121,16 +124,18 @@
#define QPNP_IADC_DATA0 0x60
#define QPNP_IADC_DATA1 0x61
-#define QPNP_ADC_CONV_TIME_MIN 2000
-#define QPNP_ADC_CONV_TIME_MAX 2200
+#define QPNP_ADC_CONV_TIME_MIN 8000
+#define QPNP_ADC_CONV_TIME_MAX 8200
-#define QPNP_ADC_GAIN_CALCULATION 2500
+#define QPNP_ADC_GAIN_CALCULATION_UV 17857
+#define QPNP_IADC_RSENSE_MILLI_FACTOR 1000
struct qpnp_iadc_drv {
struct qpnp_adc_drv *adc;
int32_t rsense;
struct device *iadc_hwmon;
bool iadc_init_calib;
+ bool iadc_initialized;
struct sensor_device_attribute sens_attr[0];
};
@@ -223,6 +228,31 @@
return IRQ_HANDLED;
}
+static int32_t qpnp_iadc_enable(bool state)
+{
+ int rc = 0;
+ u8 data = 0;
+
+ data = QPNP_IADC_ADC_EN;
+ if (state) {
+ rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+ data);
+ if (rc < 0) {
+ pr_err("IADC enable failed\n");
+ return rc;
+ }
+ } else {
+ rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+ (~data & QPNP_IADC_ADC_EN));
+ if (rc < 0) {
+ pr_err("IADC disable failed\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
static int32_t qpnp_iadc_read_conversion_result(int32_t *data)
{
uint8_t rslt_lsb, rslt_msb;
@@ -242,12 +272,9 @@
*data = (rslt_msb << 8) | rslt_lsb;
- rc = qpnp_vadc_check_result(data);
- if (rc < 0) {
- pr_err("VADC data check failed\n");
+ rc = qpnp_iadc_enable(false);
+ if (rc)
return rc;
- }
-
return 0;
}
@@ -259,10 +286,7 @@
u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
int32_t rc = 0;
- qpnp_iadc_mode_reg |= (QPNP_IADC_USE_BMS_DATA | QPNP_IADC_USE_BMS_DATA
- | QPNP_IADC_OFFSET_RMV_EN | QPNP_IADC_ADC_TRIM_EN);
-
- qpnp_iadc_ch_sel_reg = channel << QPNP_IADC_ADC_CHX_SEL_SHIFT;
+ qpnp_iadc_ch_sel_reg = channel;
qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
QPNP_IADC_DEC_RATIO_SEL;
@@ -310,6 +334,10 @@
return rc;
}
+ rc = qpnp_iadc_enable(true);
+ if (rc)
+ return rc;
+
rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
@@ -353,17 +381,53 @@
return rc;
}
+static int32_t qpnp_iadc_version_check(void)
+{
+ uint8_t revision;
+ int rc;
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed with %d\n", rc);
+ return rc;
+ }
+
+ if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
+ pr_err("IADC Version not supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int32_t qpnp_iadc_is_ready(void)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_is_ready);
+
int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
int32_t *result)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
int32_t vsense_mv = 0, rc;
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+
mutex_lock(&iadc->adc->adc_lock);
if (!iadc->iadc_init_calib) {
+ rc = qpnp_iadc_version_check();
+ if (rc)
+ goto fail;
rc = qpnp_iadc_init_calib();
- if (!rc) {
+ if (rc) {
pr_err("Calibration failed\n");
goto fail;
} else
@@ -376,12 +440,11 @@
goto fail;
}
- vsense_mv = ((*result - iadc->adc->calib.offset)/
- (iadc->adc->calib.gain - iadc->adc->calib.offset))
- * QPNP_ADC_GAIN_CALCULATION;
+ *result = ((vsense_mv - iadc->adc->calib.offset) *
+ QPNP_ADC_GAIN_CALCULATION_UV)/
+ (iadc->adc->calib.gain - iadc->adc->calib.offset);
- *result = (vsense_mv/qpnp_iadc->rsense);
-
+ *result = (*result / (qpnp_iadc->rsense));
fail:
mutex_unlock(&iadc->adc->adc_lock);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 9e8a2e2..a0e7ab9 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -32,6 +32,15 @@
#include <linux/platform_device.h>
/* QPNP VADC register definition */
+#define QPNP_VADC_REVISION1 0x0
+#define QPNP_VADC_REVISION2 0x1
+#define QPNP_VADC_REVISION3 0x2
+#define QPNP_VADC_REVISION4 0x3
+#define QPNP_VADC_PERPH_TYPE 0x4
+#define QPNP_VADC_PERH_SUBTYPE 0x5
+
+#define QPNP_VADC_SUPPORTED_REVISION2 1
+
#define QPNP_VADC_STATUS1 0x8
#define QPNP_VADC_STATUS1_OP_MODE 4
#define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
@@ -98,6 +107,8 @@
struct dentry *dent;
struct device *vadc_hwmon;
bool vadc_init_calib;
+ bool vadc_initialized;
+ int max_channels_available;
struct sensor_device_attribute sens_attr[0];
};
@@ -105,6 +116,9 @@
static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
[SCALE_DEFAULT] = {qpnp_adc_scale_default},
+ [SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
+ [SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
+ [SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
};
static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
@@ -206,32 +220,21 @@
u8 mode_ctrl = 0;
int rc = 0;
- if (vadc->vadc_init_calib) {
- /* Configure interrupt if calibration is complete */
- rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
- QPNP_VADC_INT_EOC_BIT);
- if (rc < 0) {
- pr_err("Configure error for interrupt setup\n");
- return rc;
- }
+ rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
+ QPNP_VADC_INT_EOC_BIT);
+ if (rc < 0) {
+ pr_err("Configure error for interrupt setup\n");
+ return rc;
}
/* Mode selection */
- rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode_ctrl);
- if (rc < 0) {
- pr_err("Mode configure read error\n");
- return rc;
- }
- mode_ctrl |= chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
+ mode_ctrl = chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
if (rc < 0) {
pr_err("Mode configure write error\n");
return rc;
}
- rc = qpnp_vadc_enable(true);
- if (rc)
- return rc;
/* Channel selection */
rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
@@ -242,12 +245,7 @@
}
/* Digital parameter setup */
- rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &decimation);
- if (rc < 0) {
- pr_err("Digital parameter configure read error\n");
- return rc;
- }
- decimation |= chan_prop->decimation <<
+ decimation = chan_prop->decimation <<
QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
if (rc < 0) {
@@ -296,6 +294,12 @@
}
}
+ INIT_COMPLETION(vadc->adc->adc_rslt_completion);
+
+ rc = qpnp_vadc_enable(true);
+ if (rc)
+ return rc;
+
/* Request conversion */
rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
if (rc < 0) {
@@ -402,6 +406,25 @@
return IRQ_HANDLED;
}
+static int32_t qpnp_vadc_version_check(void)
+{
+ uint8_t revision;
+ int rc;
+
+ rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed with %d\n", rc);
+ return rc;
+ }
+
+ if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
+ pr_err("VADC Version not supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static uint32_t qpnp_vadc_calib_device(void)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -421,8 +444,7 @@
goto calib_fail;
}
- while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
- QPNP_VADC_STATUS1_EOC)) {
+ while (status1 != QPNP_VADC_STATUS1_EOC) {
rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
@@ -449,8 +471,7 @@
}
status1 = 0;
- while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
- QPNP_VADC_STATUS1_EOC)) {
+ while (status1 != QPNP_VADC_STATUS1_EOC) {
rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
@@ -459,7 +480,7 @@
QPNP_VADC_CONV_TIME_MAX);
}
- rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+ rc = qpnp_vadc_read_conversion_result(&calib_read_2);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
goto calib_fail;
@@ -467,6 +488,7 @@
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
(calib_read_1 - calib_read_2);
+
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
= QPNP_ADC_625_UV;
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
@@ -486,8 +508,7 @@
}
status1 = 0;
- while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
- QPNP_VADC_STATUS1_EOC)) {
+ while (status1 != QPNP_VADC_STATUS1_EOC) {
rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
@@ -502,7 +523,7 @@
goto calib_fail;
}
- conv.amux_channel = VDD_VADC;
+ conv.amux_channel = GND_REF;
conv.decimation = DECIMATION_TYPE2;
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -514,8 +535,7 @@
}
status1 = 0;
- while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
- QPNP_VADC_STATUS1_EOC)) {
+ while (status1 != QPNP_VADC_STATUS1_EOC) {
rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
@@ -524,7 +544,7 @@
QPNP_VADC_CONV_TIME_MAX);
}
- rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+ rc = qpnp_vadc_read_conversion_result(&calib_read_2);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
goto calib_fail;
@@ -543,14 +563,31 @@
return rc;
}
+int32_t qpnp_vadc_is_ready(void)
+{
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+ if (!vadc || !vadc->vadc_initialized)
+ return -EPROBE_DEFER;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_vadc_is_ready);
+
int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
- int rc = 0, scale_type, amux_prescaling;
+ int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+
+ if (!vadc || !vadc->vadc_initialized)
+ return -EPROBE_DEFER;
if (!vadc->vadc_init_calib) {
+ rc = qpnp_vadc_version_check();
+ if (rc)
+ return rc;
rc = qpnp_vadc_calib_device();
if (rc) {
pr_err("Calibration failed\n");
@@ -562,12 +599,20 @@
mutex_lock(&vadc->adc->adc_lock);
vadc->adc->amux_prop->amux_channel = channel;
+
+ while (vadc->adc->adc_channels[dt_index].channel_num
+ != channel || dt_index > vadc->max_channels_available)
+ dt_index++;
+
+ if (dt_index > vadc->max_channels_available)
+ goto fail_unlock;
+
vadc->adc->amux_prop->decimation =
- vadc->adc->adc_channels[channel].adc_decimation;
+ vadc->adc->adc_channels[dt_index].adc_decimation;
vadc->adc->amux_prop->hw_settle_time =
- vadc->adc->adc_channels[channel].hw_settle_time;
+ vadc->adc->adc_channels[dt_index].hw_settle_time;
vadc->adc->amux_prop->fast_avg_setup =
- vadc->adc->adc_channels[channel].fast_avg_setup;
+ vadc->adc->adc_channels[dt_index].fast_avg_setup;
if (trigger_channel < ADC_SEQ_NONE)
vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
@@ -602,14 +647,15 @@
goto fail_unlock;
}
- amux_prescaling = vadc->adc->adc_channels[channel].chan_path_prescaling;
+ amux_prescaling =
+ vadc->adc->adc_channels[dt_index].chan_path_prescaling;
vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
- scale_type = vadc->adc->adc_channels[channel].adc_scale_fn;
+ scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
if (scale_type >= SCALE_NONE) {
rc = -EBADF;
goto fail_unlock;
@@ -642,8 +688,10 @@
rc = qpnp_vadc_read(attr->index, &result);
- if (rc)
+ if (rc) {
+ pr_err("VADC read error with %d\n", rc);
return 0;
+ }
return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
"Result:%lld Raw:%d\n", result.physical, result.adc_code);
@@ -738,6 +786,8 @@
dev_err(&spmi->dev,
"failed to request adc irq with error %d\n", rc);
return rc;
+ } else {
+ enable_irq_wake(vadc->adc->adc_irq);
}
qpnp_vadc = vadc;
@@ -749,6 +799,8 @@
}
vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
vadc->vadc_init_calib = false;
+ vadc->vadc_initialized = true;
+ vadc->max_channels_available = count_adc_channel_list;
rc = qpnp_vadc_configure_interrupt();
if (rc) {
@@ -777,6 +829,7 @@
i++;
}
free_irq(vadc->adc->adc_irq, vadc);
+ vadc->vadc_initialized = false;
dev_set_drvdata(&spmi->dev, NULL);
return 0;
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index de31859..c7f6b82 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -256,19 +256,30 @@
SET_SMR_MASK(base, num, 0);
SET_SMR_ID(base, num, sids[i]);
- /* Set VMID = 0 */
SET_S2CR_N(base, num, 0);
SET_S2CR_CBNDX(base, num, ctx);
+ SET_S2CR_MEMATTR(base, num, 0x0A);
/* Set security bit override to be Non-secure */
SET_S2CR_NSCFG(base, num, 3);
}
SET_CBAR_N(base, ctx, 0);
+
/* Stage 1 Context with Stage 2 bypass */
SET_CBAR_TYPE(base, ctx, 1);
+
/* Route page faults to the non-secure interrupt */
SET_CBAR_IRPTNDX(base, ctx, 1);
+ /* Set VMID to non-secure HLOS */
+ SET_CBAR_VMID(base, ctx, 3);
+
+ /* Bypass is treated as inner-shareable */
+ SET_CBAR_BPSHCFG(base, ctx, 2);
+
+ /* Do not downgrade memory attributes */
+ SET_CBAR_MEMATTR(base, ctx, 0x0A);
+
/* Find if this page table is used elsewhere, and re-use ASID */
found = 0;
for (i = 0; i < ncb; i++)
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index c5abd76..e9b4e2b 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -254,6 +254,15 @@
---help---
Enable support for Mercury Jpeg Engine
+config MSM_JPEG
+ tristate "Qualcomm MSM Jpeg Encoder Engine support"
+ depends on MSM_CAMERA && ARCH_MSM8974
+ ---help---
+ Enable support for Jpeg Encoder/Decoder
+ Engine for 8974.
+ This module serves as the common driver
+ for the JPEG 1.0 encoder and decoder.
+
config MSM_VPE
tristate "Qualcomm MSM Video Pre-processing Engine support"
depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 740e424..5921632 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -20,7 +20,7 @@
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
obj-$(CONFIG_MSM_CAMERA) += vfe/
-obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/
+obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/ jpeg_10/
obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
obj-$(CONFIG_ARCH_MSM8X60) += msm_vpe.o
diff --git a/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h b/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h
index 68c78d5..2d489b9 100644
--- a/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h
+++ b/drivers/media/video/msm/cci/msm_cam_cci_hwreg.h
@@ -26,6 +26,7 @@
#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c
#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118
#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110
+#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C
#define CCI_HALT_REQ_ADDR 0x00000034
#define CCI_M0_HALT_REQ_RMSK 0x1
#define CCI_M1_HALT_REQ_RMSK 0x01
diff --git a/drivers/media/video/msm/cci/msm_cci.c b/drivers/media/video/msm/cci/msm_cci.c
index 77bd91e..09dfd7c 100644
--- a/drivers/media/video/msm/cci/msm_cci.c
+++ b/drivers/media/video/msm/cci/msm_cci.c
@@ -221,7 +221,7 @@
{
uint32_t rc = 0;
uint32_t val = 0;
- int32_t read_bytes = 0;
+ int32_t read_words = 0, exp_words = 0;
int32_t index = 0, first_byte = 0;
uint32_t i = 0;
enum cci_i2c_master_t master;
@@ -291,7 +291,15 @@
wait_for_completion_interruptible_timeout(&cci_dev->
cci_master_info[master].reset_complete, CCI_TIMEOUT);
- read_bytes = (read_cfg->num_byte / 4) + 1;
+ read_words = msm_camera_io_r(cci_dev->base +
+ CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
+ exp_words = ((read_cfg->num_byte / 4) + 1);
+ if (read_words != exp_words) {
+ pr_err("%s:%d read_words = %d, exp words = %d\n", __func__,
+ __LINE__, read_words, exp_words);
+ memset(read_cfg->data, 0, read_cfg->num_byte);
+ goto ERROR;
+ }
index = 0;
CDBG("%s index %d num_type %d\n", __func__, index,
read_cfg->num_byte);
@@ -313,7 +321,7 @@
index++;
}
}
- } while (--read_bytes > 0);
+ } while (--read_words > 0);
ERROR:
mutex_unlock(&cci_dev->cci_master_info[master].mutex);
return rc;
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
index b66bee0..4682f8f 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_csid_hwreg.h
@@ -46,7 +46,7 @@
#define CSID_RST_DONE_IRQ_BITSHIFT 11
#define CSID_RST_STB_ALL 0x7FFF
#define CSID_DL_INPUT_SEL_SHIFT 0x2
-#define CSID_PHY_SEL_SHIFT 0x17
+#define CSID_PHY_SEL_SHIFT 17
#define CSID_VERSION 0x02000011
#endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
index ca21238..11a04d5 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_csid_hwreg.h
@@ -46,7 +46,7 @@
#define CSID_RST_DONE_IRQ_BITSHIFT 11
#define CSID_RST_STB_ALL 0x7FFF
#define CSID_DL_INPUT_SEL_SHIFT 0x4
-#define CSID_PHY_SEL_SHIFT 0x17
+#define CSID_PHY_SEL_SHIFT 17
#define CSID_VERSION 0x30000000
#endif
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index e5258f1..6274a20 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -95,10 +95,11 @@
return -EINVAL;
}
- CDBG("%s csid_params, lane_cnt = %d, lane_assign = %x\n",
+ CDBG("%s csid_params, lane_cnt = %d, lane_assign = %x, phy sel = %d\n",
__func__,
csid_params->lane_cnt,
- csid_params->lane_assign);
+ csid_params->lane_assign,
+ csid_params->phy_sel);
val = csid_params->lane_cnt - 1;
val |= csid_params->lane_assign << CSID_DL_INPUT_SEL_SHIFT;
if (csid_dev->hw_version < 0x30000000) {
@@ -169,13 +170,47 @@
{"csi_pclk", -1},
};
-static struct msm_cam_clk_info csid_8974_clk_info[] = {
- {"csi_ahb_clk", -1},
- {"csi_src_clk", 200000000},
- {"csi_clk", -1},
- {"csi_phy_clk", -1},
- {"csi_pix_clk", -1},
- {"csi_rdi_clk", -1},
+static struct msm_cam_clk_info csid0_8974_clk_info[] = {
+ {"csi0_ahb_clk", -1},
+ {"csi0_src_clk", 200000000},
+ {"csi0_clk", -1},
+ {"csi0_phy_clk", -1},
+ {"csi0_pix_clk", -1},
+ {"csi0_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_info csid1_8974_clk_info[] = {
+ {"csi1_ahb_clk", -1},
+ {"csi1_src_clk", 200000000},
+ {"csi1_clk", -1},
+ {"csi1_phy_clk", -1},
+ {"csi1_pix_clk", -1},
+ {"csi1_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_info csid2_8974_clk_info[] = {
+ {"csi2_ahb_clk", -1},
+ {"csi2_src_clk", 200000000},
+ {"csi2_clk", -1},
+ {"csi2_phy_clk", -1},
+ {"csi2_pix_clk", -1},
+ {"csi2_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_info csid3_8974_clk_info[] = {
+ {"csi3_ahb_clk", -1},
+ {"csi3_src_clk", 200000000},
+ {"csi3_clk", -1},
+ {"csi3_phy_clk", -1},
+ {"csi3_pix_clk", -1},
+ {"csi3_rdi_clk", -1},
+};
+
+static struct msm_cam_clk_setting csid_8974_clk_info[] = {
+ {&csid0_8974_clk_info[0], ARRAY_SIZE(csid0_8974_clk_info)},
+ {&csid1_8974_clk_info[0], ARRAY_SIZE(csid1_8974_clk_info)},
+ {&csid2_8974_clk_info[0], ARRAY_SIZE(csid2_8974_clk_info)},
+ {&csid3_8974_clk_info[0], ARRAY_SIZE(csid3_8974_clk_info)},
};
static struct camera_vreg_t csid_8960_vreg_info[] = {
@@ -189,6 +224,7 @@
static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
{
int rc = 0;
+ uint8_t core_id = 0;
if (!csid_version) {
pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
@@ -232,7 +268,7 @@
csid_8960_clk_info, csid_dev->csid_clk,
ARRAY_SIZE(csid_8960_clk_info), 1);
if (rc < 0) {
- pr_err("%s: regulator enable failed\n", __func__);
+ pr_err("%s: clock enable failed\n", __func__);
goto clk_enable_failed;
}
} else if (CSID_VERSION == CSID_VERSION_V3) {
@@ -253,11 +289,23 @@
}
rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
- csid_8974_clk_info, csid_dev->csid_clk,
- ARRAY_SIZE(csid_8974_clk_info), 1);
+ csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
+ csid_8974_clk_info[0].num_clk_info, 1);
if (rc < 0) {
- pr_err("%s: regulator enable failed\n", __func__);
- goto clk_enable_failed;
+ pr_err("%s: clock enable failed\n", __func__);
+ goto csid0_clk_enable_failed;
+ }
+ core_id = csid_dev->pdev->id;
+ if (core_id) {
+ rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8974_clk_info[core_id].clk_info,
+ csid_dev->csid_clk,
+ csid_8974_clk_info[core_id].num_clk_info, 1);
+ if (rc < 0) {
+ pr_err("%s: clock enable failed\n",
+ __func__);
+ goto clk_enable_failed;
+ }
}
}
@@ -274,6 +322,12 @@
return rc;
clk_enable_failed:
+ if (CSID_VERSION == CSID_VERSION_V3) {
+ msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
+ csid_8974_clk_info[0].num_clk_info, 0);
+ }
+csid0_clk_enable_failed:
if (CSID_VERSION <= CSID_VERSION_V2) {
msm_camera_enable_vreg(&csid_dev->pdev->dev,
csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
@@ -302,6 +356,7 @@
static int msm_csid_release(struct csid_device *csid_dev)
{
uint32_t irq;
+ uint8_t core_id = 0;
if (csid_dev->csid_state != CSID_POWER_UP) {
pr_err("%s: csid invalid state %d\n", __func__,
@@ -327,8 +382,16 @@
csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 0);
} else if (csid_dev->hw_version == CSID_VERSION_V3) {
- msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8974_clk_info,
- csid_dev->csid_clk, ARRAY_SIZE(csid_8974_clk_info), 0);
+ core_id = csid_dev->pdev->id;
+ if (core_id)
+ msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8974_clk_info[core_id].clk_info,
+ csid_dev->csid_clk,
+ csid_8974_clk_info[core_id].num_clk_info, 0);
+
+ msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8974_clk_info[0].clk_info, csid_dev->csid0_clk,
+ csid_8974_clk_info[0].num_clk_info, 0);
msm_camera_enable_vreg(&csid_dev->pdev->dev,
csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index 1d4de01..46e8117 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -36,7 +36,8 @@
uint32_t hw_version;
enum msm_csid_state_t csid_state;
- struct clk *csid_clk[5];
+ struct clk *csid0_clk[6];
+ struct clk *csid_clk[6];
};
#define VIDIOC_MSM_CSID_CFG \
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index bbaa0da..e3f1ebe 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -264,8 +264,8 @@
for (i = 0; i < params_len; i++) {
intftype = ispif_params[i].intftype;
vfe_intf = ispif_params[i].vfe_intf;
- CDBG("%s intftype %x, vfe_intf %d\n", __func__, intftype,
- vfe_intf);
+ CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__,
+ intftype, vfe_intf, ispif_params[i].csid);
if ((intftype >= INTF_MAX) ||
(ispif->csid_version <= CSID_VERSION_V2 &&
vfe_intf > VFE0) ||
diff --git a/drivers/media/video/msm/jpeg_10/Makefile b/drivers/media/video/msm/jpeg_10/Makefile
new file mode 100644
index 0000000..d99d1a4
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/Makefile
@@ -0,0 +1,3 @@
+GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
new file mode 100644
index 0000000..88ec1ad
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_common.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_COMMON_H
+#define MSM_JPEG_COMMON_H
+
+#ifdef MSM_JPEG_DEBUG
+#define JPEG_DBG(fmt, args...) printk(fmt, ##args)
+#else
+#define JPEG_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define JPEG_PR_ERR pr_err
+
+enum JPEG_MODE {
+ JPEG_MODE_DISABLE,
+ JPEG_MODE_OFFLINE,
+ JPEG_MODE_REALTIME,
+ JPEG_MODE_REALTIME_ROTATION
+};
+
+enum JPEG_ROTATION {
+ JPEG_ROTATION_0,
+ JPEG_ROTATION_90,
+ JPEG_ROTATION_180,
+ JPEG_ROTATION_270
+};
+
+#endif /* MSM_JPEG_COMMON_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
new file mode 100644
index 0000000..7905ff3
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2012,The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+
+static struct msm_jpeg_hw_pingpong fe_pingpong_buf;
+static struct msm_jpeg_hw_pingpong we_pingpong_buf;
+static int we_pingpong_index;
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int msm_jpeg_core_reset(uint8_t op_mode, void *base, int size)
+{
+ unsigned long flags;
+ int rc = 0;
+ int tm = 500; /*500ms*/
+ memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
+ fe_pingpong_buf.is_fe = 1;
+ we_pingpong_index = 0;
+ memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ msm_jpeg_hw_reset(base, size);
+ spin_unlock_irqrestore(&reset_lock, flags);
+ rc = wait_event_interruptible_timeout(
+ reset_wait,
+ reset_done_ack,
+ msecs_to_jiffies(tm));
+
+ if (!reset_done_ack) {
+ JPEG_DBG("%s: reset ACK failed %d", __func__, rc);
+ return -EBUSY;
+ }
+
+ JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ return 0;
+}
+
+void msm_jpeg_core_release(int release_buf, int domain_num)
+{
+ int i = 0;
+ for (i = 0; i < 2; i++) {
+ if (we_pingpong_buf.buf_status[i] && release_buf)
+ msm_jpeg_platform_p2v(we_pingpong_buf.buf[i].file,
+ &we_pingpong_buf.buf[i].handle, domain_num);
+ we_pingpong_buf.buf_status[i] = 0;
+ }
+}
+
+void msm_jpeg_core_init(void)
+{
+ init_waitqueue_head(&reset_wait);
+ spin_lock_init(&reset_lock);
+}
+
+int msm_jpeg_core_fe_start(void)
+{
+ msm_jpeg_hw_fe_start();
+ return 0;
+}
+
+/* fetch engine */
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf)
+{
+ JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+ (int) buf->y_buffer_addr, buf->y_len,
+ (int) buf->cbcr_buffer_addr, buf->cbcr_len);
+ return msm_jpeg_hw_pingpong_update(&fe_pingpong_buf, buf);
+}
+
+void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, void *context)
+{
+ return msm_jpeg_hw_pingpong_irq(&fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf)
+{
+ JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+ (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+ buf->y_len);
+ we_pingpong_buf.buf[0] = *buf;
+ we_pingpong_buf.buf_status[0] = 1;
+ msm_jpeg_hw_we_buffer_update(
+ &we_pingpong_buf.buf[0], 0);
+
+ return 0;
+}
+
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf)
+{
+ int i = 0;
+ for (i = 0; i < 2; i++) {
+ if (we_pingpong_buf.buf[i].y_buffer_addr
+ == buf->y_buffer_addr)
+ we_pingpong_buf.buf_status[i] = 0;
+ }
+ return 0;
+}
+
+void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, void *context)
+{
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+ return msm_jpeg_hw_pingpong_irq(&we_pingpong_buf);
+}
+
+void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, void *context)
+{
+ struct msm_jpeg_hw_buf *buf_p;
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+ buf_p = msm_jpeg_hw_pingpong_active_buffer(&we_pingpong_buf);
+ if (buf_p) {
+ buf_p->framedone_len = msm_jpeg_hw_encode_output_size();
+ JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+ buf_p->framedone_len);
+ }
+
+ return buf_p;
+}
+
+void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, void *context)
+{
+ /* @todo return the status back to msm_jpeg_core_reset */
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ return NULL;
+}
+
+void *msm_jpeg_core_err_irq(int jpeg_irq_status, void *context)
+{
+ JPEG_PR_ERR("%s:%d]\n", __func__, jpeg_irq_status);
+ return NULL;
+}
+
+static int (*msm_jpeg_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
+{
+ void *data = NULL;
+ unsigned long flags;
+ int jpeg_irq_status;
+
+ JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+ jpeg_irq_status = msm_jpeg_hw_irq_get_status();
+
+ JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
+ jpeg_irq_status);
+
+ /*For reset and framedone IRQs, clear all bits*/
+ if (jpeg_irq_status & 0x10000000) {
+ msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+ JPEG_IRQ_CLEAR_ALL);
+ } else if (jpeg_irq_status & 0x1) {
+ msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+ JPEG_IRQ_CLEAR_ALL);
+ } else {
+ msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
+ jpeg_irq_status);
+ }
+
+ if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
+ data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
+ context);
+ if (msm_jpeg_irq_handler)
+ msm_jpeg_irq_handler(
+ MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
+ context, data);
+ }
+ if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
+ data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
+ context);
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 1;
+ spin_unlock_irqrestore(&reset_lock, flags);
+ wake_up(&reset_wait);
+ if (msm_jpeg_irq_handler)
+ msm_jpeg_irq_handler(
+ MSM_JPEG_HW_MASK_COMP_RESET_ACK,
+ context, data);
+ }
+
+ /* Unexpected/unintended HW interrupt */
+ if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
+ data = msm_jpeg_core_err_irq(jpeg_irq_status, context);
+ if (msm_jpeg_irq_handler)
+ msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
+ context, data);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+ msm_jpeg_irq_handler = irq_handler;
+}
+
+void msm_jpeg_core_irq_remove(void)
+{
+ msm_jpeg_irq_handler = NULL;
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
new file mode 100644
index 0000000..b5c725c
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_core.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_CORE_H
+#define MSM_JPEG_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_jpeg_hw.h"
+
+#define msm_jpeg_core_buf msm_jpeg_hw_buf
+
+irqreturn_t msm_jpeg_core_irq(int irq_num, void *context);
+
+void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_jpeg_core_irq_remove(void);
+
+int msm_jpeg_core_fe_buf_update(struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_update(struct msm_jpeg_core_buf *buf);
+int msm_jpeg_core_we_buf_reset(struct msm_jpeg_hw_buf *buf);
+
+int msm_jpeg_core_reset(uint8_t op_mode, void *base, int size);
+int msm_jpeg_core_fe_start(void);
+
+void msm_jpeg_core_release(int, int);
+void msm_jpeg_core_init(void);
+#endif /* MSM_JPEG_CORE_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
new file mode 100644
index 0000000..45a9a38
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+#include <linux/of.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/msm_jpeg.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "msm.h"
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_common.h"
+
+#define MSM_JPEG_NAME "jpeg"
+#define MSM_JPEGE1_NAME "jpege1"
+#define MSM_JPEGD_NAME "jpegd"
+
+
+static int msm_jpeg_open(struct inode *inode, struct file *filp)
+{
+ int rc = 0;
+
+ struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev,
+ struct msm_jpeg_device, cdev);
+ filp->private_data = pgmn_dev;
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = __msm_jpeg_open(pgmn_dev);
+
+ JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+ return rc;
+}
+
+static int msm_jpeg_release(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+ JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__);
+
+ rc = __msm_jpeg_release(pgmn_dev);
+
+ JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+ return rc;
+}
+
+static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+ struct msm_jpeg_device *pgmn_dev = filp->private_data;
+
+ JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__,
+ __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg);
+
+ rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg);
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+static const struct file_operations msm_jpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_jpeg_open,
+ .release = msm_jpeg_release,
+ .unlocked_ioctl = msm_jpeg_ioctl,
+};
+
+
+int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd)
+{
+ int rc;
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *)jpeg_sd->host_priv;
+
+ JPEG_DBG("%s:%d: jpeg_sd=0x%x pgmn_dev=0x%x\n",
+ __func__, __LINE__, (uint32_t)jpeg_sd, (uint32_t)pgmn_dev);
+ rc = __msm_jpeg_open(pgmn_dev);
+ JPEG_DBG("%s:%d: rc=%d\n",
+ __func__, __LINE__, rc);
+ return rc;
+}
+
+static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ long rc;
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *)sd->host_priv;
+
+ JPEG_DBG("%s: cmd=%d\n", __func__, cmd);
+
+ JPEG_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+ JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__);
+
+ rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+ pr_debug("%s: X\n", __func__);
+ return rc;
+}
+
+void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd)
+{
+ int rc;
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *)jpeg_sd->host_priv;
+ JPEG_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+ rc = __msm_jpeg_release(pgmn_dev);
+ JPEG_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = {
+ .ioctl = msm_jpeg_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = {
+ .core = &msm_jpeg_subdev_core_ops,
+};
+
+static int msm_jpeg_init_dev(struct platform_device *pdev)
+{
+ int rc = -1;
+ struct device *dev;
+ struct msm_jpeg_device *msm_jpeg_device_p;
+ char devname[10];
+
+ msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
+ if (!msm_jpeg_device_p) {
+ JPEG_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+
+ msm_jpeg_device_p->pdev = pdev;
+
+ if (pdev->dev.of_node)
+ of_property_read_u32((&pdev->dev)->of_node, "cell-index",
+ &pdev->id);
+
+ snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
+
+ rc = __msm_jpeg_init(msm_jpeg_device_p);
+ if (rc < -1) {
+ JPEG_PR_ERR("%s: initialization failed\n", __func__);
+ goto fail;
+ }
+
+ v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops);
+ v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p);
+ JPEG_DBG("%s: msm_jpeg_device_p 0x%x", __func__,
+ (uint32_t)msm_jpeg_device_p);
+
+ rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1,
+ devname);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+ goto fail_1;
+ }
+
+ if (!msm_jpeg_device_p->msm_jpeg_class) {
+ msm_jpeg_device_p->msm_jpeg_class =
+ class_create(THIS_MODULE, devname);
+ if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) {
+ rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class);
+ JPEG_PR_ERR("%s: create device class failed\n",
+ __func__);
+ goto fail_2;
+ }
+ }
+
+ dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL,
+ MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno),
+ MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL,
+ "%s%d", MSM_JPEG_NAME, pdev->id);
+ if (IS_ERR(dev)) {
+ JPEG_PR_ERR("%s: error creating device\n", __func__);
+ rc = -ENODEV;
+ goto fail_3;
+ }
+
+ cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops);
+ msm_jpeg_device_p->cdev.owner = THIS_MODULE;
+ msm_jpeg_device_p->cdev.ops =
+ (const struct file_operations *) &msm_jpeg_fops;
+ rc = cdev_add(&msm_jpeg_device_p->cdev,
+ msm_jpeg_device_p->msm_jpeg_devno, 1);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: error adding cdev\n", __func__);
+ rc = -ENODEV;
+ goto fail_4;
+ }
+
+ platform_set_drvdata(pdev, &msm_jpeg_device_p);
+
+ JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id);
+
+ return rc;
+
+fail_4:
+ device_destroy(msm_jpeg_device_p->msm_jpeg_class,
+ msm_jpeg_device_p->msm_jpeg_devno);
+
+fail_3:
+ class_destroy(msm_jpeg_device_p->msm_jpeg_class);
+
+fail_2:
+ unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
+
+fail_1:
+ __msm_jpeg_exit(msm_jpeg_device_p);
+
+fail:
+ kfree(msm_jpeg_device_p);
+ return rc;
+
+}
+
+static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p)
+{
+ cdev_del(&msm_jpeg_device_p->cdev);
+ device_destroy(msm_jpeg_device_p->msm_jpeg_class,
+ msm_jpeg_device_p->msm_jpeg_devno);
+ class_destroy(msm_jpeg_device_p->msm_jpeg_class);
+ unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
+
+ __msm_jpeg_exit(msm_jpeg_device_p);
+}
+
+static int __msm_jpeg_probe(struct platform_device *pdev)
+{
+ return msm_jpeg_init_dev(pdev);
+}
+
+static int __msm_jpeg_remove(struct platform_device *pdev)
+{
+ struct msm_jpeg_device *msm_jpegd_device_p;
+
+ msm_jpegd_device_p = platform_get_drvdata(pdev);
+ if (msm_jpegd_device_p)
+ msm_jpeg_exit(msm_jpegd_device_p);
+
+ return 0;
+}
+
+static const struct of_device_id msm_jpeg_dt_match[] = {
+ {.compatible = "qcom,jpeg"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match);
+
+static struct platform_driver msm_jpeg_driver = {
+ .probe = __msm_jpeg_probe,
+ .remove = __msm_jpeg_remove,
+ .driver = {
+ .name = MSM_JPEG_DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_jpeg_dt_match,
+ },
+};
+
+static int __init msm_jpeg_driver_init(void)
+{
+ int rc;
+ rc = platform_driver_register(&msm_jpeg_driver);
+ return rc;
+}
+
+static void __exit msm_jpeg_driver_exit(void)
+{
+ platform_driver_unregister(&msm_jpeg_driver);
+}
+
+MODULE_DESCRIPTION("msm jpeg jpeg driver");
+
+module_init(msm_jpeg_driver_init);
+module_exit(msm_jpeg_driver_exit);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
new file mode 100644
index 0000000..0bfb6a8
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
@@ -0,0 +1,380 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "msm_jpeg_hw.h"
+#include "msm_jpeg_common.h"
+
+#include <linux/io.h>
+
+static void *jpeg_region_base;
+static uint32_t jpeg_region_size;
+
+int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+ struct msm_jpeg_hw_buf *buf)
+{
+ int buf_free_index = -1;
+
+ if (!pingpong_hw->buf_status[0]) {
+ buf_free_index = 0;
+ } else if (!pingpong_hw->buf_status[1]) {
+ buf_free_index = 1;
+ } else {
+ JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
+ __func__, __LINE__);
+ return -EBUSY;
+ }
+
+ pingpong_hw->buf[buf_free_index] = *buf;
+ pingpong_hw->buf_status[buf_free_index] = 1;
+
+ if (pingpong_hw->is_fe) {
+ /* it is fe */
+ msm_jpeg_hw_fe_buffer_update(
+ &pingpong_hw->buf[buf_free_index], buf_free_index);
+ } else {
+ /* it is we */
+ msm_jpeg_hw_we_buffer_update(
+ &pingpong_hw->buf[buf_free_index], buf_free_index);
+ }
+ return 0;
+}
+
+void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw)
+{
+ struct msm_jpeg_hw_buf *buf_p = NULL;
+
+ if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+ buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+ pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+ }
+
+ pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+ return (void *) buf_p;
+}
+
+void *msm_jpeg_hw_pingpong_active_buffer(
+ struct msm_jpeg_hw_pingpong *pingpong_hw)
+{
+ struct msm_jpeg_hw_buf *buf_p = NULL;
+
+ if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+ buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+ return (void *) buf_p;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR,
+ JPEG_IRQ_STATUS_BMSK, {0} },
+};
+
+int msm_jpeg_hw_irq_get_status(void)
+{
+ uint32_t n_irq_status = 0;
+ rmb();
+ n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0]);
+ rmb();
+ return n_irq_status;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_READ, 1,
+ JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR,
+ JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } ,
+};
+
+long msm_jpeg_hw_encode_output_size(void)
+{
+ uint32_t encode_output_size = 0;
+
+ encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0]);
+
+ return encode_output_size;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_irq_clear[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
+ JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} },
+};
+
+void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data)
+{
+ JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+ hw_cmd_irq_clear[0].mask = mask;
+ hw_cmd_irq_clear[0].data = data;
+ msm_jpeg_hw_write(&hw_cmd_irq_clear[0]);
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+ JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
+ JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR,
+ JPEG_PLN0_RD_OFFSET_BMSK, {0} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR,
+ JPEG_PLN0_RD_PNTR_BMSK, {0} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR,
+ JPEG_PLN1_RD_OFFSET_BMSK, {0} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR,
+ JPEG_PLN1_RD_PNTR_BMSK, {0} },
+};
+
+void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+ uint8_t pingpong_index)
+{
+ struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+ if (pingpong_index == 0) {
+ hw_cmd_p = &hw_cmd_fe_ping_update[0];
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ hw_cmd_p->data = p_input->y_buffer_addr;
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ hw_cmd_p->data = p_input->cbcr_buffer_addr;
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+
+ }
+ return;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
+ JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_jpeg_hw_fe_start(void)
+{
+ msm_jpeg_hw_write(&hw_cmd_fe_start[0]);
+
+ return;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR,
+ JPEG_PLN0_WR_PNTR_BMSK, {0} },
+};
+
+void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+ uint8_t pingpong_index)
+{
+ struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+ if (pingpong_index == 0) {
+ hw_cmd_p = &hw_cmd_we_ping_update[0];
+ hw_cmd_p->data = p_input->y_buffer_addr;
+ JPEG_PR_ERR("%s Output buffer address is %x\n", __func__,
+ p_input->y_buffer_addr);
+ msm_jpeg_hw_write(hw_cmd_p++);
+
+ }
+ return;
+}
+
+struct msm_jpeg_hw_cmd hw_cmd_reset[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+ JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
+ JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
+ JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+ {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR,
+ JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_jpeg_hw_init(void *base, int size)
+{
+ jpeg_region_base = base;
+ jpeg_region_size = size;
+}
+
+void msm_jpeg_hw_reset(void *base, int size)
+{
+ struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+ hw_cmd_p = &hw_cmd_reset[0];
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p++);
+ wmb();
+ msm_jpeg_hw_write(hw_cmd_p);
+ wmb();
+
+ return;
+}
+
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t data;
+
+ paddr = jpeg_region_base + hw_cmd_p->offset;
+
+ data = readl_relaxed(paddr);
+ data &= hw_cmd_p->mask;
+
+ return data;
+}
+
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t old_data, new_data;
+
+ paddr = jpeg_region_base + hw_cmd_p->offset;
+
+ if (hw_cmd_p->mask == 0xffffffff) {
+ old_data = 0;
+ } else {
+ old_data = readl_relaxed(paddr);
+ old_data &= ~hw_cmd_p->mask;
+ }
+
+ new_data = hw_cmd_p->data & hw_cmd_p->mask;
+ new_data |= old_data;
+ writel_relaxed(new_data, paddr);
+}
+
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ uint32_t data;
+ uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+ data = msm_jpeg_hw_read(hw_cmd_p);
+ if (data != wait_data) {
+ while (tm) {
+ udelay(m_us);
+ data = msm_jpeg_hw_read(hw_cmd_p);
+ if (data == wait_data)
+ break;
+ tm--;
+ }
+ }
+ hw_cmd_p->data = data;
+ return tm;
+}
+
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ while (tm) {
+ udelay(m_us);
+ tm--;
+ }
+}
+
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds)
+{
+ int is_copy_to_user = -1;
+ uint32_t data;
+
+ while (m_cmds--) {
+ if (hw_cmd_p->offset > jpeg_region_size) {
+ JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+ __LINE__, hw_cmd_p->offset, jpeg_region_size);
+ return -EFAULT;
+ }
+
+ switch (hw_cmd_p->type) {
+ case MSM_JPEG_HW_CMD_TYPE_READ:
+ hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p);
+ is_copy_to_user = 1;
+ break;
+
+ case MSM_JPEG_HW_CMD_TYPE_WRITE:
+ msm_jpeg_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
+ data = msm_jpeg_hw_read(hw_cmd_p);
+ hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+ data;
+ msm_jpeg_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_JPEG_HW_CMD_TYPE_UWAIT:
+ msm_jpeg_hw_wait(hw_cmd_p, 1);
+ break;
+
+ case MSM_JPEG_HW_CMD_TYPE_MWAIT:
+ msm_jpeg_hw_wait(hw_cmd_p, 1000);
+ break;
+
+ case MSM_JPEG_HW_CMD_TYPE_UDELAY:
+ msm_jpeg_hw_delay(hw_cmd_p, 1);
+ break;
+
+ case MSM_JPEG_HW_CMD_TYPE_MDELAY:
+ msm_jpeg_hw_delay(hw_cmd_p, 1000);
+ break;
+
+ default:
+ JPEG_PR_ERR("wrong hw command type\n");
+ break;
+ }
+
+ hw_cmd_p++;
+ }
+ return is_copy_to_user;
+}
+
+void msm_jpeg_io_dump(int size)
+{
+ char line_str[128], *p_str;
+ void __iomem *addr = jpeg_region_base;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ JPEG_PR_ERR("%s: %p %d reg_size %d\n", __func__, addr, size,
+ jpeg_region_size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ JPEG_PR_ERR("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ JPEG_PR_ERR("%s\n", line_str);
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
new file mode 100644
index 0000000..73a0e27
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_HW_H
+#define MSM_JPEG_HW_H
+
+#include <media/msm_jpeg.h>
+#include "msm_jpeg_hw_reg.h"
+#include <linux/ion.h>
+#include <mach/iommu_domains.h>
+
+struct msm_jpeg_hw_buf {
+ struct msm_jpeg_buf vbuf;
+ struct file *file;
+ uint32_t framedone_len;
+ uint32_t y_buffer_addr;
+ uint32_t y_len;
+ uint32_t cbcr_buffer_addr;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ struct ion_handle *handle;
+};
+
+struct msm_jpeg_hw_pingpong {
+ uint8_t is_fe; /* 1: fe; 0: we */
+ struct msm_jpeg_hw_buf buf[2];
+ int buf_status[2];
+ int buf_active_index;
+};
+
+int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
+ struct msm_jpeg_hw_buf *buf);
+void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw);
+void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong
+ *pingpong_hw);
+
+void msm_jpeg_hw_irq_clear(uint32_t, uint32_t);
+int msm_jpeg_hw_irq_get_status(void);
+long msm_jpeg_hw_encode_output_size(void);
+#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \
+ MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_JPEG_HW_MASK_COMP_FE \
+ MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_JPEG_HW_MASK_COMP_WE \
+ (MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \
+ MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_JPEG_HW_MASK_COMP_ERR \
+ (MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+ MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \
+ (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE)
+#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \
+ (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE)
+#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \
+ (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE)
+#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \
+ (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK)
+#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \
+ (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR)
+
+void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
+ uint8_t pingpong_index);
+void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
+ uint8_t pingpong_index);
+
+void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_jpeg_hw_fe_start(void);
+void msm_jpeg_hw_clk_cfg(void);
+
+void msm_jpeg_hw_reset(void *base, int size);
+void msm_jpeg_hw_irq_cfg(void);
+void msm_jpeg_hw_init(void *base, int size);
+
+uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p);
+void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p);
+int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
+void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_jpeg_hw_region_dump(int size);
+void msm_jpeg_io_dump(int size);
+
+#endif /* MSM_JPEG_HW_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
new file mode 100644
index 0000000..ae64c32
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_HW_REG_H
+#define MSM_JPEG_HW_REG_H
+
+#define JPEG_REG_BASE 0
+
+#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018
+#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF
+#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF
+
+#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
+#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
+
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
+#define MSM_JPEG_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
+
+#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000
+#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
+#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+
+#define JPEG_OFFLINE_CMD_START 0x00000001
+
+#define JPEG_RESET_DEFAULT 0x00000003 /* cfff? */
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
+
+#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038)
+#define JPEG_PLN0_RD_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C
+#define JPEG_PLN0_RD_OFFSET_BMSK 0x1FFFFFFF
+
+#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044)
+#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048
+#define JPEG_PLN1_RD_OFFSET_BMSK 0x1FFFFFFF
+
+#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010)
+#define JPEG_CMD_BMSK 0x00000FFF
+#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700
+
+#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc)
+#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0)
+#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF
+
+#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018)
+#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
+
+#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c)
+#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF
+
+#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008)
+#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF
+
+#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020)
+#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF
+
+#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180)
+#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF
+
+
+#define VBIF_BASE_ADDRESS 0xFDA60000
+#define VBIF_REGION_SIZE 0xC30
+#define JPEG_VBIF_CLKON 0x4
+#define JPEG_VBIF_IN_RD_LIM_CONF0 0xB0
+#define JPEG_VBIF_IN_RD_LIM_CONF1 0xB4
+#define JPEG_VBIF_IN_RD_LIM_CONF2 0xB8
+#define JPEG_VBIF_IN_WR_LIM_CONF0 0xC0
+#define JPEG_VBIF_IN_WR_LIM_CONF1 0xC4
+#define JPEG_VBIF_IN_WR_LIM_CONF2 0xC8
+#define JPEG_VBIF_OUT_RD_LIM_CONF0 0xD0
+#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4
+#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8
+#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC
+
+#endif /* MSM_JPEG_HW_REG_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
new file mode 100644
index 0000000..981c56c
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/camera.h>
+#include <mach/iommu_domains.h>
+
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_common.h"
+#include "msm_jpeg_hw.h"
+
+/* AXI rate in KHz */
+struct ion_client *jpeg_client;
+static void *jpeg_vbif;
+
+void msm_jpeg_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle, int domain_num)
+{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(jpeg_client, *ionhandle, domain_num, 0);
+ ion_free(jpeg_client, *ionhandle);
+ *ionhandle = NULL;
+#elif CONFIG_ANDROID_PMEM
+ put_pmem_file(file);
+#endif
+}
+
+uint32_t msm_jpeg_platform_v2p(int fd, uint32_t len, struct file **file_p,
+ struct ion_handle **ionhandle, int domain_num)
+{
+ unsigned long paddr;
+ unsigned long size;
+ int rc;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ *ionhandle = ion_import_dma_buf(jpeg_client, fd);
+ if (IS_ERR_OR_NULL(*ionhandle))
+ return 0;
+
+ rc = ion_map_iommu(jpeg_client, *ionhandle, domain_num, 0,
+ SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
+ JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__,
+ (uint32_t)paddr, size);
+
+#elif CONFIG_ANDROID_PMEM
+ unsigned long kvstart;
+ rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
+#else
+ rc = 0;
+ paddr = 0;
+ size = 0;
+#endif
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+ rc);
+ goto error1;
+ }
+
+ /* validate user input */
+ if (len > size) {
+ JPEG_PR_ERR("%s: invalid offset + len\n", __func__);
+ goto error1;
+ }
+
+ return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_free(jpeg_client, *ionhandle);
+#endif
+ return 0;
+}
+
+static struct msm_cam_clk_info jpeg_8x_clk_info[] = {
+ {"core_clk", 228570000},
+ {"iface_clk", -1},
+ {"bus_clk0", -1},
+ {"alt_bus_clk", -1},
+ {"camss_top_ahb_clk", -1},
+};
+
+static void set_vbif_params(void *jpeg_vbif_base)
+{
+ writel_relaxed(0x1,
+ jpeg_vbif_base + JPEG_VBIF_CLKON);
+ writel_relaxed(0x10101010,
+ jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0);
+ writel_relaxed(0x10101010,
+ jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1);
+ writel_relaxed(0x10101010,
+ jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2);
+ writel_relaxed(0x10101010,
+ jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0);
+ writel_relaxed(0x10101010,
+ jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1);
+ writel_relaxed(0x10101010,
+ jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2);
+ writel_relaxed(0x00001010,
+ jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0);
+ writel_relaxed(0x00001010,
+ jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0);
+ writel_relaxed(0x00000707,
+ jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST);
+ writel_relaxed(0x00000707,
+ jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST);
+}
+
+
+int msm_jpeg_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context)
+{
+ int rc = -1;
+ int i = 0;
+ int jpeg_irq;
+ struct resource *jpeg_mem, *jpeg_io, *jpeg_irq_res;
+ void *jpeg_base;
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *) context;
+
+ jpeg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!jpeg_mem) {
+ JPEG_PR_ERR("%s: no mem resource?\n", __func__);
+ return -ENODEV;
+ }
+
+ jpeg_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!jpeg_irq_res) {
+ JPEG_PR_ERR("no irq resource?\n");
+ return -ENODEV;
+ }
+ jpeg_irq = jpeg_irq_res->start;
+ JPEG_DBG("%s base address: 0x%x, jpeg irq number: %d\n", __func__,
+ jpeg_mem->start, jpeg_irq);
+
+ jpeg_io = request_mem_region(jpeg_mem->start,
+ resource_size(jpeg_mem), pdev->name);
+ if (!jpeg_io) {
+ JPEG_PR_ERR("%s: region already claimed\n", __func__);
+ return -EBUSY;
+ }
+
+ jpeg_base = ioremap(jpeg_mem->start, resource_size(jpeg_mem));
+ if (!jpeg_base) {
+ rc = -ENOMEM;
+ JPEG_PR_ERR("%s: ioremap failed\n", __func__);
+ goto fail1;
+ }
+
+ jpeg_vbif = ioremap(VBIF_BASE_ADDRESS, VBIF_REGION_SIZE);
+ if (!jpeg_vbif) {
+ rc = -ENOMEM;
+ JPEG_PR_ERR("%s:%d] ioremap failed\n", __func__, __LINE__);
+ goto fail1;
+ }
+ JPEG_DBG("%s:%d] jpeg_vbif 0x%x", __func__, __LINE__,
+ (uint32_t)jpeg_vbif);
+
+ pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd");
+ rc = regulator_enable(pgmn_dev->jpeg_fs);
+ if (rc) {
+ JPEG_PR_ERR("%s:%d]jpeg regulator get failed\n",
+ __func__, __LINE__); }
+
+ pgmn_dev->hw_version = JPEG_8974;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
+ pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 1);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+ goto fail2;
+ }
+
+#ifdef CONFIG_MSM_IOMMU
+ for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+ rc = iommu_attach_device(pgmn_dev->domain,
+ pgmn_dev->iommu_ctx_arr[i]);
+ if (rc < 0) {
+ rc = -ENODEV;
+ JPEG_PR_ERR("%s: Device attach failed\n", __func__);
+ goto fail;
+ }
+ JPEG_DBG("%s:%d] dom 0x%x ctx 0x%x", __func__, __LINE__,
+ (uint32_t)pgmn_dev->domain,
+ (uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+ }
+#endif
+ set_vbif_params(jpeg_vbif);
+
+ msm_jpeg_hw_init(jpeg_base, resource_size(jpeg_mem));
+ rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg",
+ context);
+ if (rc) {
+ JPEG_PR_ERR("%s: request_irq failed, %d\n", __func__,
+ jpeg_irq);
+ goto fail3;
+ }
+
+ *mem = jpeg_mem;
+ *base = jpeg_base;
+ *irq = jpeg_irq;
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ jpeg_client = msm_ion_client_create(-1, "camera/jpeg");
+#endif
+ JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+
+ return rc;
+
+fail3:
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
+ pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
+
+ regulator_put(pgmn_dev->jpeg_fs);
+ regulator_disable(pgmn_dev->jpeg_fs);
+ pgmn_dev->jpeg_fs = NULL;
+fail2:
+ iounmap(jpeg_base);
+fail1:
+#ifdef CONFIG_MSM_IOMMU
+ for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+ JPEG_PR_ERR("%s:%d] dom 0x%x ctx 0x%x", __func__, __LINE__,
+ (uint32_t)pgmn_dev->domain,
+ (uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+ iommu_detach_device(pgmn_dev->domain,
+ pgmn_dev->iommu_ctx_arr[i]);
+ }
+#endif
+fail:
+ release_mem_region(jpeg_mem->start, resource_size(jpeg_mem));
+ JPEG_DBG("%s:%d] fail\n", __func__, __LINE__);
+ return rc;
+}
+
+int msm_jpeg_platform_release(struct resource *mem, void *base, int irq,
+ void *context)
+{
+ int result = 0;
+ int i = 0;
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *) context;
+
+ free_irq(irq, context);
+
+#ifdef CONFIG_MSM_IOMMU
+ for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+ iommu_detach_device(pgmn_dev->domain,
+ pgmn_dev->iommu_ctx_arr[i]);
+ JPEG_DBG("%s:%d]", __func__, __LINE__);
+ }
+#endif
+
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info,
+ pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
+ JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
+
+ if (pgmn_dev->jpeg_fs) {
+ regulator_put(pgmn_dev->jpeg_fs);
+ regulator_disable(pgmn_dev->jpeg_fs);
+ pgmn_dev->jpeg_fs = NULL;
+ }
+ iounmap(jpeg_vbif);
+ iounmap(base);
+ release_mem_region(mem->start, resource_size(mem));
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_client_destroy(jpeg_client);
+#endif
+ JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+ return result;
+}
+
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
new file mode 100644
index 0000000..8a37cef
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_JPEG_PLATFORM_H
+#define MSM_JPEG_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu.h>
+
+
+void msm_jpeg_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle, int domain_num);
+uint32_t msm_jpeg_platform_v2p(int fd, uint32_t len, struct file **file,
+ struct ion_handle **ionhandle, int domain_num);
+
+int msm_jpeg_platform_clk_enable(void);
+int msm_jpeg_platform_clk_disable(void);
+
+int msm_jpeg_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context);
+int msm_jpeg_platform_release(struct resource *mem, void *base, int irq,
+ void *context);
+
+#endif /* MSM_JPEG_PLATFORM_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
new file mode 100644
index 0000000..6ac4a5e
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -0,0 +1,897 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_jpeg.h>
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+
+static int release_buf;
+
+inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
+{
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+ q_p->name = name;
+ spin_lock_init(&q_p->lck);
+ INIT_LIST_HEAD(&q_p->q);
+ init_waitqueue_head(&q_p->wait);
+ q_p->unblck = 0;
+}
+
+inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p)
+{
+ unsigned long flags;
+ struct msm_jpeg_q_entry *q_entry_p = NULL;
+ void *data = NULL;
+
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ spin_lock_irqsave(&q_p->lck, flags);
+ if (!list_empty(&q_p->q)) {
+ q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry,
+ list);
+ list_del_init(&q_entry_p->list);
+ }
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ if (q_entry_p) {
+ data = q_entry_p->data;
+ kfree(q_entry_p);
+ } else {
+ JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+ q_p->name);
+ }
+
+ return data;
+}
+
+inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data)
+{
+ unsigned long flags;
+
+ struct msm_jpeg_q_entry *q_entry_p;
+
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+ q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC);
+ if (!q_entry_p) {
+ JPEG_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+ q_entry_p->data = data;
+
+ spin_lock_irqsave(&q_p->lck, flags);
+ list_add_tail(&q_entry_p->list, &q_p->q);
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ return 0;
+}
+
+inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p,
+ struct msm_jpeg_core_buf *buf)
+{
+ struct msm_jpeg_core_buf *buf_p;
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ JPEG_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+
+ memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf));
+
+ msm_jpeg_q_in(q_p, buf_p);
+ return 0;
+}
+
+inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p)
+{
+ int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+ int rc;
+
+ JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+ rc = wait_event_interruptible_timeout(q_p->wait,
+ (!list_empty_careful(&q_p->q) || q_p->unblck),
+ msecs_to_jiffies(tm));
+ JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+ if (list_empty_careful(&q_p->q)) {
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+ q_p->name);
+ } else if (q_p->unblck) {
+ JPEG_DBG("%s:%d] %s unblock is true\n", __func__,
+ __LINE__, q_p->name);
+ q_p->unblck = 0;
+ rc = -ECANCELED;
+ } else if (rc < 0) {
+ JPEG_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__,
+ q_p->name, rc);
+ }
+ }
+ return rc;
+}
+
+inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p)
+{
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p)
+{
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = 1;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_q *q_p,
+ int domain_num)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ buf_p = msm_jpeg_q_out(q_p);
+ if (buf_p) {
+ msm_jpeg_platform_p2v(buf_p->file,
+ &buf_p->handle, domain_num);
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(buf_p);
+ }
+ } while (buf_p);
+ q_p->unblck = 0;
+}
+
+inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p)
+{
+ void *data;
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ data = msm_jpeg_q_out(q_p);
+ if (data) {
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(data);
+ }
+ } while (data);
+ q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf_in)
+{
+ int rc = 0;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ if (buf_in) {
+ buf_in->vbuf.framedone_len = buf_in->framedone_len;
+ buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE;
+ JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+ __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len,
+ buf_in->vbuf.framedone_len);
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in);
+ } else {
+ JPEG_PR_ERR("%s:%d] no output return buffer\n",
+ __func__, __LINE__);
+ rc = -1;
+ }
+
+ if (buf_in)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+ return rc;
+}
+
+int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev,
+ void __user *to)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_ctrl_cmd ctrl_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_jpeg_q_wait(&pgmn_dev->evt_q);
+ buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q);
+
+ if (!buf_p) {
+ JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ ctrl_cmd.type = buf_p->vbuf.type;
+ kfree(buf_p);
+
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) ctrl_cmd.value, ctrl_cmd.len);
+
+ if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+ JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_unblock(&pgmn_dev->evt_q);
+ return 0;
+}
+
+void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev,
+ int event)
+{
+ int rc = 0;
+ struct msm_jpeg_core_buf buf;
+
+ JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+ buf.vbuf.type = MSM_JPEG_EVT_ERR;
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf);
+ if (!rc)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+ if (!rc)
+ JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+ return;
+}
+
+/*************** output queue ****************/
+
+int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf_in)
+{
+ int rc = 0;
+ struct msm_jpeg_core_buf *buf_out;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (buf_in) {
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+ } else {
+ JPEG_DBG("%s:%d] no output return buffer\n", __func__,
+ __LINE__);
+ rc = -1;
+ return rc;
+ }
+
+ buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out) {
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_out->y_buffer_addr, buf_out->y_len);
+ rc = msm_jpeg_core_we_buf_update(buf_out);
+ kfree(buf_out);
+ } else {
+ msm_jpeg_core_we_buf_reset(buf_in);
+ JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+ rc = -2;
+ }
+
+ if (buf_in)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q);
+
+ return rc;
+}
+
+int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_buf buf_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_jpeg_q_wait(&pgmn_dev->output_rtn_q);
+ buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q);
+
+ if (!buf_p) {
+ JPEG_DBG("%s:%d] no output buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
+ pgmn_dev->domain_num);
+ kfree(buf_p);
+
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ JPEG_PR_ERR("%s:%d]", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q);
+ return 0;
+}
+
+int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_jpeg_buf buf_cmd;
+ struct msm_jpeg_core_buf *buf_p;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ JPEG_DBG("%s:%d] vaddr = 0x%08x y_len = %d\n, fd = %d",
+ __func__, __LINE__, (int) buf_cmd.vaddr, buf_cmd.y_len,
+ buf_cmd.fd);
+
+ buf_p->y_buffer_addr = msm_jpeg_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &buf_p->file, &buf_p->handle,
+ pgmn_dev->domain_num);
+ if (!buf_p->y_buffer_addr) {
+ JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -EFAULT;
+ }
+ JPEG_DBG("%s:%d]After v2p y_address =0x%08x, handle = %p\n",
+ __func__, __LINE__, buf_p->y_buffer_addr, buf_p->handle);
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->vbuf = buf_cmd;
+
+ msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p);
+ return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf_in)
+{
+ struct msm_jpeg_core_buf *buf_out;
+ int rc = 0;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (buf_in) {
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+ } else {
+ JPEG_DBG("%s:%d] no input return buffer\n", __func__,
+ __LINE__);
+ rc = -EFAULT;
+ }
+
+ buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ rc = msm_jpeg_core_fe_buf_update(buf_out);
+ kfree(buf_out);
+ msm_jpeg_core_fe_start();
+ } else {
+ JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+ rc = -EFAULT;
+ }
+
+ if (buf_in)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q);
+
+ return rc;
+}
+
+int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_buf buf_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_wait(&pgmn_dev->input_rtn_q);
+ buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q);
+
+ if (!buf_p) {
+ JPEG_DBG("%s:%d] no input buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ msm_jpeg_platform_p2v(buf_p->file, &buf_p->handle,
+ pgmn_dev->domain_num);
+ kfree(buf_p);
+
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q);
+ return 0;
+}
+
+int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_buf buf_cmd;
+
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ buf_p->y_buffer_addr = msm_jpeg_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
+ &buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset
+ + buf_cmd.y_off;
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
+ + buf_cmd.cbcr_off;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
+ buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+ JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%x, fd =%d\n",
+ __func__, buf_p->y_buffer_addr, buf_p->y_len,
+ buf_p->cbcr_buffer_addr, buf_p->cbcr_len, buf_cmd.fd);
+
+ if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+ JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -EFAULT;
+ }
+ buf_p->vbuf = buf_cmd;
+
+ msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+ return 0;
+}
+
+int msm_jpeg_irq(int event, void *context, void *data)
+{
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *) context;
+
+ switch (event) {
+ case MSM_JPEG_EVT_SESSION_DONE:
+ msm_jpeg_framedone_irq(pgmn_dev, data);
+ msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_FE:
+ msm_jpeg_fe_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_WE:
+ msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_RESET_ACK:
+ msm_jpeg_reset_ack_irq(pgmn_dev);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_ERR:
+ default:
+ msm_jpeg_err_irq(pgmn_dev, event);
+ break;
+ }
+
+ return 0;
+}
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev)
+{
+ int rc;
+
+ mutex_lock(&pgmn_dev->lock);
+ if (pgmn_dev->open_count) {
+ /* only open once */
+ JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EBUSY;
+ }
+ pgmn_dev->open_count++;
+ mutex_unlock(&pgmn_dev->lock);
+
+ msm_jpeg_core_irq_install(msm_jpeg_irq);
+ rc = msm_jpeg_platform_init(pgmn_dev->pdev,
+ &pgmn_dev->mem, &pgmn_dev->base,
+ &pgmn_dev->irq, msm_jpeg_core_irq, pgmn_dev);
+ if (rc) {
+ JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+ __LINE__, rc);
+ return rc;
+ }
+
+ JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
+ __func__, __LINE__,
+ pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+
+ msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(&pgmn_dev->output_buf_q,
+ pgmn_dev->domain_num); msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q);
+ msm_jpeg_core_init();
+
+ JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+ return rc;
+}
+
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ mutex_lock(&pgmn_dev->lock);
+ if (!pgmn_dev->open_count) {
+ JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EINVAL;
+ }
+ pgmn_dev->open_count--;
+ mutex_unlock(&pgmn_dev->lock);
+
+ msm_jpeg_core_release(release_buf, pgmn_dev->domain_num);
+ msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(&pgmn_dev->output_buf_q,
+ pgmn_dev->domain_num);
+ msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(&pgmn_dev->input_buf_q, pgmn_dev->domain_num);
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ if (pgmn_dev->open_count)
+ JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+ msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base,
+ pgmn_dev->irq, pgmn_dev);
+
+ return 0;
+}
+
+int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_jpeg_hw_cmd hw_cmd;
+ int is_copy_to_user;
+
+ if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1);
+ JPEG_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x,pdata %x\n",
+ __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+ hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ int is_copy_to_user;
+ int len;
+ uint32_t m;
+ struct msm_jpeg_hw_cmds *hw_cmds_p;
+ struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len = sizeof(struct msm_jpeg_hw_cmds) +
+ sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
+ hw_cmds_p = kmalloc(len, GFP_KERNEL);
+ if (!hw_cmds_p) {
+ JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(hw_cmds_p, arg, len)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+
+ hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, hw_cmds_p, len)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+ }
+ kfree(hw_cmds_p);
+ return 0;
+}
+
+int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg)
+{
+ struct msm_jpeg_core_buf *buf_out;
+ struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL};
+ int i, rc;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ release_buf = 1;
+ for (i = 0; i < 2; i++) {
+ buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ msm_jpeg_core_fe_buf_update(buf_out);
+ kfree(buf_out);
+ } else {
+ JPEG_DBG("%s:%d] no input buffer\n", __func__,
+ __LINE__);
+ break;
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out_free[i]) {
+ msm_jpeg_core_we_buf_update(buf_out_free[i]);
+ release_buf = 0;
+ } else {
+ JPEG_DBG("%s:%d] no output buffer\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ kfree(buf_out_free[i]);
+
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg);
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ int rc;
+ struct msm_jpeg_ctrl_cmd ctrl_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ pgmn_dev->op_mode = ctrl_cmd.type;
+
+ rc = msm_jpeg_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+ resource_size(pgmn_dev->mem));
+ return rc;
+}
+
+int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev,
+ unsigned long arg)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_io_dump(arg);
+ return 0;
+}
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ switch (cmd) {
+ case MSM_JPEG_IOCTL_GET_HW_VERSION:
+ JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+ rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_RESET:
+ rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_STOP:
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_START:
+ rc = msm_jpeg_start(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE:
+ rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET:
+ rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK:
+ rc = msm_jpeg_input_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE:
+ rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET:
+ rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK:
+ rc = msm_jpeg_output_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET:
+ rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_jpeg_evt_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMD:
+ rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMDS:
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_TEST_DUMP_REGION:
+ rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+ break;
+
+ default:
+ JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
+ __func__, __LINE__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static int camera_register_domain(void)
+{
+ struct msm_iova_partition camera_fw_partition = {
+ .start = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ };
+
+ struct msm_iova_layout camera_fw_layout = {
+ .partitions = &camera_fw_partition,
+ .npartitions = 1,
+ .client_name = "camera_jpeg",
+ .domain_flags = 0,
+ };
+ return msm_register_domain(&camera_fw_layout);
+}
+#endif
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev)
+{
+ int rc = 0, i = 0;
+ int idx = 0;
+ char *iommu_name[3] = {"jpeg_enc0", "jpeg_enc1", "jpeg_dec"};
+
+ mutex_init(&pgmn_dev->lock);
+
+ pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__,
+ pgmn_dev->pdev->id);
+ idx = pgmn_dev->pdev->id;
+ pgmn_dev->idx = idx;
+ pgmn_dev->iommu_cnt = 1;
+
+ msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q);
+ msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+ msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+ msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+ msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+#ifdef CONFIG_MSM_IOMMU
+/*get device context for IOMMU*/
+ for (i = 0; i < pgmn_dev->iommu_cnt; i++) {
+ pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[i]);
+ JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[i]);
+ JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__,
+ (uint32_t)pgmn_dev->iommu_ctx_arr[i]);
+ if (!pgmn_dev->iommu_ctx_arr[i]) {
+ JPEG_PR_ERR("%s: No iommu fw context found\n",
+ __func__);
+ goto error;
+ }
+ }
+ pgmn_dev->domain_num = camera_register_domain();
+ JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__,
+ pgmn_dev->domain_num);
+ if (pgmn_dev->domain_num < 0) {
+ JPEG_PR_ERR("%s: could not register domain\n", __func__);
+ goto error;
+ }
+ pgmn_dev->domain = msm_get_iommu_domain(pgmn_dev->domain_num);
+ JPEG_DBG("%s:%d] dom 0x%x", __func__, __LINE__,
+ (uint32_t)pgmn_dev->domain);
+ if (!pgmn_dev->domain) {
+ JPEG_PR_ERR("%s: cannot find domain\n", __func__);
+ goto error;
+ }
+#endif
+
+ return rc;
+error:
+ mutex_destroy(&pgmn_dev->lock);
+ return -EFAULT;
+}
+
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev)
+{
+ mutex_destroy(&pgmn_dev->lock);
+ kfree(pgmn_dev);
+ return 0;
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
new file mode 100644
index 0000000..1d82060
--- /dev/null
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+
+#ifndef MSM_JPEG_SYNC_H
+#define MSM_JPEG_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_jpeg_core.h"
+
+#define JPEG_7X 0x1
+#define JPEG_8X60 (0x1 << 1)
+#define JPEG_8960 (0x1 << 2)
+#define JPEG_8974 0x1
+
+struct msm_jpeg_q {
+ char const *name;
+ struct list_head q;
+ spinlock_t lck;
+ wait_queue_head_t wait;
+ int unblck;
+};
+
+struct msm_jpeg_q_entry {
+ struct list_head list;
+ void *data;
+};
+
+struct msm_jpeg_device {
+ struct platform_device *pdev;
+ struct resource *mem;
+ int irq;
+ void *base;
+ struct clk *jpeg_clk[5];
+ struct regulator *jpeg_fs;
+ uint32_t hw_version;
+
+ struct device *device;
+ struct cdev cdev;
+ struct mutex lock;
+ char open_count;
+ uint8_t op_mode;
+
+ /* event queue including frame done & err indications
+ */
+ struct msm_jpeg_q evt_q;
+
+ /* output return queue
+ */
+ struct msm_jpeg_q output_rtn_q;
+
+ /* output buf queue
+ */
+ struct msm_jpeg_q output_buf_q;
+
+ /* input return queue
+ */
+ struct msm_jpeg_q input_rtn_q;
+
+ /* input buf queue
+ */
+ struct msm_jpeg_q input_buf_q;
+
+ struct v4l2_subdev subdev;
+
+ struct class *msm_jpeg_class;
+
+ dev_t msm_jpeg_devno;
+
+ /*iommu domain and context*/
+ int domain_num;
+ int idx;
+ struct iommu_domain *domain;
+ struct device *iommu_ctx_arr[3];
+ int iommu_cnt;
+};
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev);
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg);
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev);
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev);
+
+#endif /* MSM_JPEG_SYNC_H */
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 3dc0fe7..e4925ad 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -58,6 +58,7 @@
#define MSM_VPE_DRV_NAME "msm_vpe"
#define MSM_GEMINI_DRV_NAME "msm_gemini"
#define MSM_MERCURY_DRV_NAME "msm_mercury"
+#define MSM_JPEG_DRV_NAME "msm_jpeg"
#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
#define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
#define MSM_CPP_DRV_NAME "msm_cpp"
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 0711ca5..60f08ce 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -1163,7 +1163,7 @@
static int msm_mctl_v4l2_dqbuf(struct file *f, void *pctx,
struct v4l2_buffer *pb)
{
- int rc = 0;
+ int rc = 0, i;
/* get the camera device */
struct msm_cam_v4l2_dev_inst *pcam_inst;
pcam_inst = container_of(f->private_data,
@@ -1180,6 +1180,26 @@
rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK);
D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
+ if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ /* Reject the buffer if planes array was not allocated */
+ if (pb->m.planes == NULL) {
+ pr_err("%s Planes array is null\n", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
+ return -EINVAL;
+ }
+ for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
+ pb->m.planes[i].data_offset =
+ pcam_inst->buf_offset[pb->index][i].data_offset;
+ pb->m.planes[i].reserved[0] =
+ pcam_inst->buf_offset[pb->index][i].addr_offset;
+ D("%s update offsets for plane %d as A %d D %d\n",
+ __func__, i, pb->m.planes[i].reserved[0],
+ pb->m.planes[i].data_offset);
+ }
+ } else {
+ pb->reserved = pcam_inst->buf_offset[pb->index][0].addr_offset;
+ D("%s stored reserved info %d\n", __func__, pb->reserved);
+ }
mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index b2cddb0..a114b37 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -103,6 +103,10 @@
if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T)
*pp_type = OUTPUT_TYPE_T;
break;
+ case MSM_V4L2_EXT_CAPTURE_MODE_RDI:
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_R)
+ *pp_type = OUTPUT_TYPE_R;
+ break;
default:
break;
}
@@ -405,8 +409,8 @@
ERR_COPY_FROM_USER();
return -EFAULT;
}
- D("%s: PP_PATH, path=%d",
- __func__, divert_pp.path);
+ D("%s: Divert Image mode =%d Enable %d",
+ __func__, divert_pp.path, divert_pp.enable);
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
if (divert_pp.enable)
p_mctl->pp_info.pp_ctrl.pp_msg_type |= divert_pp.path;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 8fbcc01..03d666f 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -399,6 +399,7 @@
csi_lane_assign;
sensor_output_info->csi_lane_mask = csi_lane_params->
csi_lane_mask;
+ sensor_output_info->csi_phy_sel = csi_lane_params->csi_phy_sel;
}
sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
for (index = 0; index < sensor_output_info->csi_if; index++)
@@ -1174,6 +1175,14 @@
}
pinfo->csi_lane_params->csi_lane_mask = val;
+ rc = of_property_read_u32(of_node, "qcom,csi-phy-sel", &val);
+ CDBG("%s qcom,csi-phy-sel %x, rc %d\n", __func__, val, rc);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR3;
+ }
+ pinfo->csi_lane_params->csi_phy_sel = val;
+
kfree(val_array);
return rc;
ERROR3:
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 1423063..bc38f62 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -700,9 +700,15 @@
int_time[0] = line >> 12;
int_time[1] = line >> 4;
int_time[2] = line << 4;
- msm_camera_i2c_write_seq(s_ctrl->sensor_i2c_client,
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
- &int_time[0], 3);
+ int_time[0], MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+ int_time[1], MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1,
+ int_time[2], MSM_CAMERA_I2C_BYTE_DATA);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->global_gain_addr, gain,
MSM_CAMERA_I2C_WORD_DATA);
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index fda59db..6a2372e 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -481,7 +481,7 @@
.line_length_pclk = 5336,
.frame_length_lines = 3052,
.vt_pixel_clk = 330000000,
- .op_pixel_clk = 320000000,
+ .op_pixel_clk = 264000000,
.binning_factor = 1,
},
/* 30 fps preview */
@@ -491,7 +491,7 @@
.line_length_pclk = 4480,
.frame_length_lines = 2412,
.vt_pixel_clk = 330000000,
- .op_pixel_clk = 320000000,
+ .op_pixel_clk = 264000000,
.binning_factor = 1,
},
/* 60 fps video */
@@ -501,7 +501,7 @@
.line_length_pclk = 5336,
.frame_length_lines = 992,
.vt_pixel_clk = 330000000,
- .op_pixel_clk = 320000000,
+ .op_pixel_clk = 264000000,
.binning_factor = 1,
},
/* 90 fps video */
@@ -511,7 +511,7 @@
.line_length_pclk = 5336,
.frame_length_lines = 664,
.vt_pixel_clk = 330000000,
- .op_pixel_clk = 320000000,
+ .op_pixel_clk = 264000000,
.binning_factor = 1,
},
/* 120 fps video */
@@ -521,7 +521,7 @@
.line_length_pclk = 5336,
.frame_length_lines = 514,
.vt_pixel_clk = 330000000,
- .op_pixel_clk = 320000000,
+ .op_pixel_clk = 264000000,
.binning_factor = 1,
},
/* 24 fps snapshot */
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 1297379..e958241 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -806,7 +806,7 @@
vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
msm_camera_io_w(0x800080,
vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
- msm_camera_io_w(0xFFFFF,
+ msm_camera_io_w(0x198FFFFF,
vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
msm_camera_io_w(0,
@@ -1289,6 +1289,12 @@
vfe40_ctrl->share_ctrl->vfebase +
VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(0x00003fff,
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_AXI_BUS_CMD_OFF);
+ msm_camera_io_w_mb(1,
+ vfe40_ctrl->share_ctrl->vfebase +
+ V40_BUS_PM_CMD);
if (vfe_operation_mode) {
msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
VFE_CAMIF_COMMAND);
@@ -1345,8 +1351,6 @@
vfe40_ctrl->share_ctrl->start_ack_pending = TRUE;
vfe40_start_common(vfe40_ctrl);
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
return 0;
}
static int vfe40_capture_raw(
@@ -1381,12 +1385,9 @@
vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
- vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
vfe40_start_common(vfe40_ctrl);
/* for debug */
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
return 0;
}
@@ -1639,7 +1640,7 @@
outch = vfe40_get_ch(path, axi_ctrl->share_ctrl);
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
/* Configure Preview Ping Pong */
- pr_info("%s Configure ping/pong address for %d",
+ pr_info("%s Configure ping/pong address for %d\n",
__func__, path);
vfe40_put_ch_ping_addr(
axi_ctrl->share_ctrl->vfebase, outch->ch0,
@@ -3153,7 +3154,6 @@
irq_mask &= ~(0x1 << (share_ctrl->outpath.out3.ch0 +
VFE_WM_OFFSET));
}
-
msm_camera_io_w_mb(reg_update,
share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
msm_camera_io_w(irq_mask, share_ctrl->vfebase +
@@ -3326,7 +3326,6 @@
msm_camera_io_w(0, share_ctrl->vfebase +
vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch1]);
-
share_ctrl->liveshot_state = VFE_STATE_STOPPED;
msm_camera_io_w_mb(1, share_ctrl->vfebase +
VFE_REG_UPDATE_CMD);
@@ -3387,11 +3386,10 @@
msm_camera_io_w_mb
(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
share_ctrl->vfebase +
- VFE_CAMIF_COMMAND);
+ VFE_CAMIF_COMMAND);
vfe40_ctrl->snapshot_frame_cnt = -1;
vfe40_ctrl->frame_skip_cnt = 31;
- vfe40_ctrl->frame_skip_pattern =
- 0xffffffff;
+ vfe40_ctrl->frame_skip_pattern = 0xffffffff;
} /*if snapshot count is 0*/
} /*if frame is not being dropped*/
vfe40_ctrl->snapshot_frame_cnt++;
@@ -3607,6 +3605,8 @@
static void vfe40_process_common_error_irq(
struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
{
+ if (errStatus & VFE40_IMASK_BUS_BDG_HALT_ACK)
+ pr_err("vfe40_irq: BUS BDG HALT ACK\n");
if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL)
pr_err("vfe40_irq: image master 0 bus overflow\n");
@@ -5455,9 +5455,14 @@
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE40_OUTPUT_MODE_PRIMARY) {
- irq_comp_mask |= (
- 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
- 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
+ if (vfe_params.cmd_type == AXI_CMD_RAW_CAPTURE) {
+ irq_comp_mask |=
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0;
+ } else {
+ irq_comp_mask |= (
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
+ }
irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
} else if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
@@ -5551,12 +5556,21 @@
default:
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE40_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch1]);
+ if (vfe_params.cmd_type == AXI_CMD_RAW_CAPTURE) {
+ msm_camera_io_w(1,
+ axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ } else {
+ msm_camera_io_w(1,
+ axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl
+ ->share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1,
+ axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ }
} else if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
@@ -5592,6 +5606,7 @@
}
break;
}
+
if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 5b73751..8201d18 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -204,6 +204,7 @@
#define V40_AXI_OUT_LEN 344
#define V40_AXI_CFG_LEN 71
+#define V40_BUS_PM_CMD 0x00000270
#define V40_FOV_ENC_OFF 0x00000854
#define V40_FOV_ENC_LEN 16
#define V40_FOV_VIEW_OFF 0x00000864
@@ -719,7 +720,7 @@
#define VFE40_IMASK_ERROR_ONLY_0 0x0
/* when normal case, don't want to block error status. */
/* bit 0-21 are error irq bits */
-#define VFE40_IMASK_COMMON_ERROR_ONLY_1 0x0000FE00
+#define VFE40_IMASK_COMMON_ERROR_ONLY_1 0x0000FF00
#define VFE40_IMASK_VFE_ERROR_ONLY_1 0x00FF01FF
#define VFE40_IMASK_CAMIF_ERROR (0x00000001<<0)
#define VFE40_IMASK_BHIST_OVWR (0x00000001<<1)
@@ -729,6 +730,7 @@
#define VFE40_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<5)
#define VFE40_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<6)
#define VFE40_IMASK_VIOLATION (0x00000001<<7)
+#define VFE40_IMASK_BUS_BDG_HALT_ACK (0x00000001<<8)
#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<9)
#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<10)
#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<11)
diff --git a/drivers/media/video/msm_vidc/Makefile b/drivers/media/video/msm_vidc/Makefile
index e145229..2a1f40f 100644
--- a/drivers/media/video/msm_vidc/Makefile
+++ b/drivers/media/video/msm_vidc/Makefile
@@ -4,5 +4,6 @@
msm_vdec.o \
msm_venc.o \
msm_smem.o \
+ msm_vidc_debug.o \
vidc_hal.o \
vidc_hal_interrupt_handler.o \
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index b7b12cb..156a721 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include "msm_smem.h"
+#include "msm_vidc_debug.h"
struct smem_client {
int mem_type;
@@ -27,19 +28,20 @@
{
int rc;
if (!iova || !buffer_size || !hndl || !clnt) {
- pr_err("Invalid params: %p, %p, %p, %p\n",
+ dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
clnt, hndl, iova, buffer_size);
return -EINVAL;
}
if (align < 4096)
align = 4096;
- pr_debug("\n In %s domain: %d, Partition: %d\n",
- __func__, domain_num, partition_num);
+ dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
+ domain_num, partition_num);
rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
0, iova, buffer_size, UNCACHED, 0);
if (rc)
- pr_err("ion_map_iommu failed(%d).domain: %d,partition: %d\n",
- rc, domain_num, partition_num);
+ dprintk(VIDC_ERR,
+ "ion_map_iommu failed(%d).domain: %d,partition: %d\n",
+ rc, domain_num, partition_num);
return rc;
}
@@ -61,14 +63,14 @@
int rc = 0;
hndl = ion_import_dma_buf(client->clnt, fd);
if (IS_ERR_OR_NULL(hndl)) {
- pr_err("Failed to get handle: %p, %d, %d, %p\n",
+ dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
client, fd, offset, hndl);
rc = -ENOMEM;
goto fail_import_fd;
}
rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
if (rc) {
- pr_err("Failed to get ion flags: %d", rc);
+ dprintk(VIDC_ERR, "Failed to get ion flags: %d", rc);
goto fail_map;
}
mem->kvaddr = NULL;
@@ -77,7 +79,7 @@
rc = get_device_address(client->clnt, hndl, mem->domain,
mem->partition_num, 4096, &iova, &buffer_size, ionflag);
if (rc) {
- pr_err("Failed to get device address: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
goto fail_device_address;
}
@@ -85,7 +87,7 @@
mem->smem_priv = hndl;
mem->device_addr = iova;
mem->size = buffer_size;
- pr_err("NOTE: Buffer device address: 0x%lx, size: %d\n",
+ dprintk(VIDC_DBG, "NOTE: Buffer device address: 0x%lx, size: %d\n",
mem->device_addr, mem->size);
return rc;
fail_device_address:
@@ -114,12 +116,13 @@
if (align < 4096)
align = 4096;
size = (size + 4095) & (~4095);
- pr_debug("\n in %s domain: %d, Partition: %d\n",
- __func__, domain, partition);
+ dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
+ domain, partition);
hndl = ion_alloc(client->clnt, size, align, ionflags);
if (IS_ERR_OR_NULL(hndl)) {
- pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
- client, size, align, ionflags);
+ dprintk(VIDC_ERR,
+ "Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
+ client, size, align, ionflags);
rc = -ENOMEM;
goto fail_shared_mem_alloc;
}
@@ -130,7 +133,8 @@
if (map_kernel) {
mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
if (!mem->kvaddr) {
- pr_err("Failed to map shared mem in kernel\n");
+ dprintk(VIDC_ERR,
+ "Failed to map shared mem in kernel\n");
rc = -EIO;
goto fail_map;
}
@@ -140,11 +144,13 @@
rc = get_device_address(client->clnt, hndl, mem->domain,
mem->partition_num, align, &iova, &buffer_size, UNCACHED);
if (rc) {
- pr_err("Failed to get device address: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to get device address: %d\n",
+ rc);
goto fail_device_address;
}
mem->device_addr = iova;
- pr_err("NOTE: device_address = 0x%lx, kvaddr = 0x%p, size = %d\n",
+ dprintk(VIDC_DBG,
+ "device_address = 0x%lx, kvaddr = 0x%p, size = %d\n",
mem->device_addr, mem->kvaddr, size);
mem->size = size;
return rc;
@@ -172,7 +178,7 @@
struct ion_client *client = NULL;
client = msm_ion_client_create(-1, "video_client");
if (!client)
- pr_err("Failed to create smem client\n");
+ dprintk(VIDC_ERR, "Failed to create smem client\n");
return client;
};
@@ -188,12 +194,12 @@
int rc = 0;
struct msm_smem *mem;
if (fd < 0) {
- pr_err("Invalid fd: %d\n", fd);
+ dprintk(VIDC_ERR, "Invalid fd: %d\n", fd);
return NULL;
}
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem) {
- pr_err("Failed to allocte shared mem\n");
+ dprintk(VIDC_ERR, "Failed to allocte shared mem\n");
return NULL;
}
switch (client->mem_type) {
@@ -202,12 +208,12 @@
domain, partition, mem);
break;
default:
- pr_err("Mem type not supported\n");
+ dprintk(VIDC_ERR, "Mem type not supported\n");
rc = -EINVAL;
break;
}
if (rc) {
- pr_err("Failed to allocate shared memory\n");
+ dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
kfree(mem);
mem = NULL;
}
@@ -229,7 +235,7 @@
struct smem_client *client = clt;
int rc;
if (!client || !mem) {
- pr_err("Invalid client/handle passed\n");
+ dprintk(VIDC_ERR, "Invalid client/handle passed\n");
return -EINVAL;
}
switch (client->mem_type) {
@@ -237,7 +243,7 @@
rc = ion_mem_clean_invalidate(client, mem);
break;
default:
- pr_err("Mem type not supported\n");
+ dprintk(VIDC_ERR, "Mem type not supported\n");
rc = -EINVAL;
break;
}
@@ -253,7 +259,7 @@
clnt = ion_new_client();
break;
default:
- pr_err("Mem type not supported\n");
+ dprintk(VIDC_ERR, "Mem type not supported\n");
break;
}
if (clnt) {
@@ -263,7 +269,8 @@
client->clnt = clnt;
}
} else {
- pr_err("Failed to create new client: mtype = %d\n", mtype);
+ dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
+ mtype);
}
return client;
};
@@ -276,16 +283,17 @@
struct msm_smem *mem;
client = clt;
if (!client) {
- pr_err("Invalid client passed\n");
+ dprintk(VIDC_ERR, "Invalid client passed\n");
return NULL;
}
if (!size) {
- pr_err("No need to allocate memory of size: %d\n", size);
+ dprintk(VIDC_ERR, "No need to allocate memory of size: %d\n",
+ size);
return NULL;
}
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem) {
- pr_err("Failed to allocate shared mem\n");
+ dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
return NULL;
}
switch (client->mem_type) {
@@ -294,12 +302,12 @@
domain, partition, mem, map_kernel);
break;
default:
- pr_err("Mem type not supported\n");
+ dprintk(VIDC_ERR, "Mem type not supported\n");
rc = -EINVAL;
break;
}
if (rc) {
- pr_err("Failed to allocate shared memory\n");
+ dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
kfree(mem);
mem = NULL;
}
@@ -310,7 +318,7 @@
{
struct smem_client *client = clt;
if (!client || !mem) {
- pr_err("Invalid client/handle passed\n");
+ dprintk(VIDC_ERR, "Invalid client/handle passed\n");
return;
}
switch (client->mem_type) {
@@ -318,7 +326,7 @@
free_ion_mem(client, mem);
break;
default:
- pr_err("Mem type not supported\n");
+ dprintk(VIDC_ERR, "Mem type not supported\n");
break;
}
kfree(mem);
@@ -328,7 +336,7 @@
{
struct smem_client *client = clt;
if (!client) {
- pr_err("Invalid client passed\n");
+ dprintk(VIDC_ERR, "Invalid client passed\n");
return;
}
switch (client->mem_type) {
@@ -336,7 +344,7 @@
ion_delete_client(client);
break;
default:
- pr_err("Mem type not supported\n");
+ dprintk(VIDC_ERR, "Mem type not supported\n");
break;
}
kfree(client);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 882d03e..3b9c958 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -26,6 +26,7 @@
#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
#include "vidc_hal_api.h"
#include "msm_smem.h"
@@ -491,7 +492,7 @@
struct buffer_info *temp;
struct buffer_info *ret = NULL;
if (!list || fd < 0) {
- pr_err("%s Invalid input\n", __func__);
+ dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
if (!list_empty(list)) {
@@ -501,7 +502,8 @@
|| CONTAINS(buff_off, size, temp->buff_off)
|| OVERLAPS(buff_off, size,
temp->buff_off, temp->size))) {
- pr_err("This memory region is already mapped\n");
+ dprintk(VIDC_WARN,
+ "This memory region is already mapped\n");
ret = temp;
break;
}
@@ -517,13 +519,13 @@
struct buffer_info *temp;
struct buffer_info *ret = NULL;
if (!list || fd < 0) {
- pr_err("%s Invalid input\n", __func__);
+ dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
if (!list_empty(list)) {
list_for_each_entry(temp, list, list) {
if (temp && temp->fd == fd) {
- pr_err("Found same fd buffer\n");
+ dprintk(VIDC_ERR, "Found same fd buffer\n");
ret = temp;
break;
}
@@ -543,20 +545,22 @@
struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
GFP_KERNEL);
if (!v4l2_inst) {
- pr_err("Failed to allocate memory for this instance\n");
+ dprintk(VIDC_ERR,
+ "Failed to allocate memory for this instance\n");
rc = -ENOMEM;
goto fail_nomem;
}
v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
if (!v4l2_inst->mem_client) {
- pr_err("Failed to create memory client\n");
+ dprintk(VIDC_ERR, "Failed to create memory client\n");
rc = -ENOMEM;
goto fail_mem_client;
}
rc = msm_vidc_open(&v4l2_inst->vidc_inst, core->id, vid_dev->type);
if (rc) {
- pr_err("Failed to create video instance, core: %d, type = %d\n",
- core->id, vid_dev->type);
+ dprintk(VIDC_ERR,
+ "Failed to create video instance, core: %d, type = %d\n",
+ core->id, vid_dev->type);
rc = -ENOMEM;
goto fail_open;
}
@@ -658,10 +662,11 @@
plane.m.userptr = bi->uvaddr;
buffer_info.m.planes = &plane;
buffer_info.length = 1;
- pr_info("Releasing buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
&buffer_info);
list_del(&bi->list);
@@ -687,7 +692,7 @@
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
if (!v4l2_inst->mem_client) {
- pr_err("Failed to get memory client\n");
+ dprintk(VIDC_ERR, "Failed to get memory client\n");
rc = -ENOMEM;
goto exit;
}
@@ -697,13 +702,14 @@
b->m.planes[i].reserved[1],
b->m.planes[i].length);
if (binfo) {
- pr_err("This memory region has already been prepared\n");
+ dprintk(VIDC_WARN,
+ "This memory region has already been prepared\n");
rc = -EINVAL;
goto exit;
}
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
- pr_err("Out of memory\n");
+ dprintk(VIDC_ERR, "Out of memory\n");
rc = -ENOMEM;
goto exit;
}
@@ -725,7 +731,8 @@
vidc_inst->core->resources.io_map[NS_MAP].domain,
0);
if (!handle) {
- pr_err("Failed to get device buffer address\n");
+ dprintk(VIDC_ERR,
+ "Failed to get device buffer address\n");
kfree(binfo);
goto exit;
}
@@ -737,7 +744,7 @@
binfo->device_addr =
handle->device_addr + binfo->buff_off;
binfo->handle = handle;
- pr_debug("Registering buffer: %d, %d, %d\n",
+ dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
b->m.planes[i].length);
@@ -766,7 +773,8 @@
b->m.planes[i].reserved[1],
b->m.planes[i].length);
if (!binfo) {
- pr_err("This buffer is not registered: %d, %d, %d\n",
+ dprintk(VIDC_ERR,
+ "This buffer is not registered: %d, %d, %d\n",
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
b->m.planes[i].length);
@@ -774,13 +782,14 @@
goto err_invalid_buff;
}
b->m.planes[i].m.userptr = binfo->device_addr;
- pr_debug("Queueing device address = 0x%x\n",
+ dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
binfo->device_addr);
if (binfo->handle) {
rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
binfo->handle);
if (rc) {
- pr_err("Failed to clean caches: %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
goto err_invalid_buff;
}
}
@@ -892,21 +901,24 @@
size_t sz = 0;
struct device_node *np = pdev->dev.of_node;
if (!of_get_property(np, name, &len)) {
- pr_err("Failed to read %s from device tree\n",
+ dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
name);
goto fail_read;
}
sz = len / sizeof(u32);
if (sz <= 0) {
- pr_err("%s not specified in device tree\n", name);
+ dprintk(VIDC_ERR, "%s not specified in device tree\n",
+ name);
goto fail_read;
}
if (sz > size) {
- pr_err("Not enough memory to store %s values\n", name);
+ dprintk(VIDC_ERR, "Not enough memory to store %s values\n",
+ name);
goto fail_read;
}
if (of_property_read_u32_array(np, name, arr, sz)) {
- pr_err("error while reading %s from device tree\n",
+ dprintk(VIDC_ERR,
+ "error while reading %s from device tree\n",
name);
goto fail_read;
}
@@ -939,7 +951,8 @@
io_map[i].addr_range,
(sizeof(io_map[i].addr_range)/sizeof(u32)));
if (!len) {
- pr_err("Error in reading cp address range\n");
+ dprintk(VIDC_ERR,
+ "Error in reading cp address range\n");
rc = -EINVAL;
break;
}
@@ -959,15 +972,15 @@
layout.partitions = &partition[0];
layout.client_name = io_map[i].name;
layout.domain_flags = 0;
- pr_debug("Registering domain 1 with: %lx, %lx, %s\n",
+ dprintk(VIDC_DBG, "Registering domain 1 with: %lx, %lx, %s\n",
partition[0].start, partition[0].size,
layout.client_name);
- pr_debug("Registering domain 2 with: %lx, %lx, %s\n",
+ dprintk(VIDC_DBG, "Registering domain 2 with: %lx, %lx, %s\n",
partition[1].start, partition[1].size,
layout.client_name);
io_map[i].domain = msm_register_domain(&layout);
if (io_map[i].domain < 0) {
- pr_err("Failed to register cp domain\n");
+ dprintk(VIDC_ERR, "Failed to register cp domain\n");
rc = -EINVAL;
break;
}
@@ -987,7 +1000,7 @@
int rc = 0;
struct core_clock *clock;
if (!core) {
- pr_err("Invalid params: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid params: %p\n", core);
return -EINVAL;
}
clock = core->resources.clock;
@@ -1004,13 +1017,14 @@
"load-freq-tbl", (u32 *)clock[VCODEC_CLK].load_freq_tbl,
(sizeof(clock[VCODEC_CLK].load_freq_tbl)/sizeof(u32)));
clock[VCODEC_CLK].count /= 2;
- pr_err("NOTE: Count = %d\n", clock[VCODEC_CLK].count);
+ dprintk(VIDC_DBG, "count = %d\n", clock[VCODEC_CLK].count);
if (!clock[VCODEC_CLK].count) {
- pr_err("Failed to read clock frequency\n");
+ dprintk(VIDC_ERR, "Failed to read clock frequency\n");
goto fail_init_clocks;
}
for (i = 0; i < clock[VCODEC_CLK].count; i++) {
- pr_err("NOTE: load = %d, freq = %d\n",
+ dprintk(VIDC_DBG,
+ "load = %d, freq = %d\n",
clock[VCODEC_CLK].load_freq_tbl[i].load,
clock[VCODEC_CLK].load_freq_tbl[i].freq
);
@@ -1021,7 +1035,8 @@
if (!cl->clk) {
cl->clk = devm_clk_get(&pdev->dev, cl->name);
if (IS_ERR_OR_NULL(cl->clk)) {
- pr_err("Failed to get clock: %s\n", cl->name);
+ dprintk(VIDC_ERR,
+ "Failed to get clock: %s\n", cl->name);
rc = PTR_ERR(cl->clk);
break;
}
@@ -1042,7 +1057,7 @@
{
int i;
if (!core) {
- pr_err("Invalid args\n");
+ dprintk(VIDC_ERR, "Invalid args\n");
return;
}
for (i = 0; i < VCODEC_MAX_CLKS; i++)
@@ -1060,7 +1075,7 @@
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- pr_err("Failed to get IORESOURCE_MEM\n");
+ dprintk(VIDC_ERR, "Failed to get IORESOURCE_MEM\n");
rc = -ENODEV;
goto core_init_failed;
}
@@ -1068,7 +1083,7 @@
core->register_size = resource_size(res);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- pr_err("Failed to get IORESOURCE_IRQ\n");
+ dprintk(VIDC_ERR, "Failed to get IORESOURCE_IRQ\n");
rc = -ENODEV;
goto core_init_failed;
}
@@ -1084,37 +1099,37 @@
}
rc = msm_vidc_init_clocks(pdev, core);
if (rc) {
- pr_err("Failed to init clocks\n");
+ dprintk(VIDC_ERR, "Failed to init clocks\n");
rc = -ENODEV;
goto core_init_failed;
}
core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER] =
msm_bus_scale_register_client(&enc_ddr_bus_data);
if (!core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER]) {
- pr_err("Failed to register bus scale client\n");
+ dprintk(VIDC_ERR, "Failed to register bus scale client\n");
goto fail_register_enc_ddr_bus;
}
core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER] =
msm_bus_scale_register_client(&dec_ddr_bus_data);
if (!core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER]) {
- pr_err("Failed to register bus scale client\n");
+ dprintk(VIDC_ERR, "Failed to register bus scale client\n");
goto fail_register_dec_ddr_bus;
}
core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER] =
msm_bus_scale_register_client(&enc_ocmem_bus_data);
if (!core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER]) {
- pr_err("Failed to register bus scale client\n");
+ dprintk(VIDC_ERR, "Failed to register bus scale client\n");
goto fail_register_enc_ocmem;
}
core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER] =
msm_bus_scale_register_client(&dec_ocmem_bus_data);
if (!core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER]) {
- pr_err("Failed to register bus scale client\n");
+ dprintk(VIDC_ERR, "Failed to register bus scale client\n");
goto fail_register_dec_ocmem;
}
rc = register_iommu_domains(pdev, core);
if (rc) {
- pr_err("Failed to register iommu domains: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to register iommu domains: %d\n", rc);
goto fail_register_domains;
}
ocmem = &core->resources.ocmem;
@@ -1122,8 +1137,8 @@
ocmem->handle =
ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
if (!ocmem->handle) {
- pr_warn("Failed to register OCMEM notifier.");
- pr_warn(" Performance will be impacted\n");
+ dprintk(VIDC_WARN, "Failed to register OCMEM notifier.");
+ dprintk(VIDC_WARN, " Performance will be impacted\n");
}
return rc;
fail_register_domains:
@@ -1149,21 +1164,21 @@
int rc = 0;
struct msm_vidc_core *core;
unsigned long flags;
- char debugfs_name[MAX_DEBUGFS_NAME];
core = kzalloc(sizeof(*core), GFP_KERNEL);
if (!core || !vidc_driver) {
- pr_err("Failed to allocate memory for device core\n");
+ dprintk(VIDC_ERR,
+ "Failed to allocate memory for device core\n");
rc = -ENOMEM;
goto err_no_mem;
}
rc = msm_vidc_initialize_core(pdev, core);
if (rc) {
- pr_err("Failed to init core\n");
+ dprintk(VIDC_ERR, "Failed to init core\n");
goto err_v4l2_register;
}
rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
if (rc) {
- pr_err("Failed to register v4l2 device\n");
+ dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
goto err_v4l2_register;
}
core->vdev[MSM_VIDC_DECODER].vdev.release =
@@ -1174,7 +1189,7 @@
rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER);
if (rc) {
- pr_err("Failed to register video decoder device");
+ dprintk(VIDC_ERR, "Failed to register video decoder device");
goto err_dec_register;
}
video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
@@ -1187,7 +1202,7 @@
rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER + 1);
if (rc) {
- pr_err("Failed to register video encoder device");
+ dprintk(VIDC_ERR, "Failed to register video encoder device");
goto err_enc_register;
}
video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
@@ -1195,14 +1210,14 @@
core->register_base, core->register_size, core->irq,
&handle_cmd_response);
if (!core->device) {
- pr_err("Failed to create interrupt handler");
+ dprintk(VIDC_ERR, "Failed to create interrupt handler");
goto err_cores_exceeded;
}
spin_lock_irqsave(&vidc_driver->lock, flags);
if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) {
spin_unlock_irqrestore(&vidc_driver->lock, flags);
- pr_err("Maximum cores already exist, core_no = %d\n",
+ dprintk(VIDC_ERR, "Maximum cores already exist, core_no = %d\n",
vidc_driver->num_cores);
goto err_cores_exceeded;
}
@@ -1210,9 +1225,8 @@
core->id = vidc_driver->num_cores++;
list_add_tail(&core->list, &vidc_driver->cores);
spin_unlock_irqrestore(&vidc_driver->lock, flags);
- snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
- core->debugfs_root = debugfs_create_dir(debugfs_name,
- vidc_driver->debugfs_root);
+ core->debugfs_root = msm_vidc_debugfs_init_core(
+ core, vidc_driver->debugfs_root);
pdev->dev.platform_data = core;
return rc;
@@ -1271,7 +1285,8 @@
vidc_driver = kzalloc(sizeof(*vidc_driver),
GFP_KERNEL);
if (!vidc_driver) {
- pr_err("Failed to allocate memroy for msm_vidc_drv\n");
+ dprintk(VIDC_ERR,
+ "Failed to allocate memroy for msm_vidc_drv\n");
return -ENOMEM;
}
@@ -1279,11 +1294,13 @@
spin_lock_init(&vidc_driver->lock);
vidc_driver->debugfs_root = debugfs_create_dir("msm_vidc", NULL);
if (!vidc_driver->debugfs_root)
- pr_err("Failed to create debugfs for msm_vidc\n");
+ dprintk(VIDC_ERR,
+ "Failed to create debugfs for msm_vidc\n");
rc = platform_driver_register(&msm_vidc_driver);
if (rc) {
- pr_err("Failed to register platform driver\n");
+ dprintk(VIDC_ERR,
+ "Failed to register platform driver\n");
kfree(vidc_driver);
vidc_driver = NULL;
}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 4939b64..8240890 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -17,6 +17,7 @@
#include "msm_vidc_common.h"
#include "vidc_hal_api.h"
#include "msm_smem.h"
+#include "msm_vidc_debug.h"
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define MAX_PLANES 1
@@ -275,13 +276,14 @@
struct vb2_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", i);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
return -EINVAL;
}
- pr_debug("Calling streamon\n");
+ dprintk(VIDC_DBG, "Calling streamon\n");
rc = vb2_streamon(q, i);
if (rc)
- pr_err("streamon failed on port: %d\n", i);
+ dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
return rc;
}
@@ -292,13 +294,14 @@
q = msm_comm_get_vb2q(inst, i);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", i);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
return -EINVAL;
}
- pr_debug("Calling streamoff\n");
+ dprintk(VIDC_DBG, "Calling streamoff\n");
rc = vb2_streamoff(q, i);
if (rc)
- pr_err("streamoff failed on port: %d\n", i);
+ dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
return rc;
}
@@ -313,7 +316,7 @@
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
for (i = 0; i < b->length; i++) {
- pr_err("device_addr = %ld, size = %d\n",
+ dprintk(VIDC_DBG, "device_addr = %ld, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
buffer_info.buffer_size = b->m.planes[i].length;
@@ -328,7 +331,8 @@
inst->core->resources.io_map[NS_MAP].domain,
0, 0);
if (!inst->extradata_handle) {
- pr_err("Failed to allocate extradta memory\n");
+ dprintk(VIDC_ERR,
+ "Failed to allocate extradta memory\n");
rc = -ENOMEM;
break;
}
@@ -339,13 +343,14 @@
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
if (rc) {
- pr_err("vidc_hal_session_set_buffers failed");
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed\n");
break;
}
}
break;
default:
- pr_err("Buffer type not recognized: %d\n", b->type);
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
break;
}
return rc;
@@ -363,7 +368,8 @@
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
for (i = 0; i < b->length; i++) {
- pr_debug("Release device_addr = %ld, size = %d\n",
+ dprintk(VIDC_DBG,
+ "Release device_addr = %ld, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
buffer_info.buffer_size = b->m.planes[i].length;
@@ -376,11 +382,12 @@
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
- pr_err("vidc_hal_session_release_buffers failed");
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_release_buffers failed\n");
}
break;
default:
- pr_err("Buffer type not recognized: %d\n", b->type);
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
break;
}
return rc;
@@ -392,12 +399,13 @@
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+ , b->type);
return -EINVAL;
}
rc = vb2_qbuf(q, b);
if (rc)
- pr_err("Failed to qbuf, %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
return rc;
}
int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
@@ -406,12 +414,13 @@
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+ , b->type);
return -EINVAL;
}
rc = vb2_dqbuf(q, b, true);
if (rc)
- pr_err("Failed to dqbuf, %d\n", rc);
+ dprintk(VIDC_WARN, "Failed to dqbuf, %d\n", rc);
return rc;
}
@@ -420,18 +429,20 @@
struct vb2_queue *q = NULL;
int rc = 0;
if (!inst || !b) {
- pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, buffer = %p\n", inst, b);
return -EINVAL;
}
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+ , b->type);
return -EINVAL;
}
rc = vb2_reqbufs(q, b);
if (rc)
- pr_err("Failed to get reqbufs, %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
return rc;
}
@@ -441,7 +452,8 @@
int rc = 0;
int i;
if (!inst || !f) {
- pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -464,7 +476,7 @@
inst->prop.width);
}
} else {
- pr_err("Buf type not recognized, type = %d\n",
+ dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
f->type);
rc = -EINVAL;
}
@@ -477,7 +489,8 @@
int rc = 0;
int i;
if (!inst || !f) {
- pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -487,8 +500,9 @@
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
CAPTURE_PORT);
if (fmt && fmt->type != CAPTURE_PORT) {
- pr_err("Format: %d not supported on CAPTURE port\n",
- f->fmt.pix_mp.pixelformat);
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on CAPTURE"
+ "port\n", f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto err_invalid_fmt;
}
@@ -499,12 +513,14 @@
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
frame_sz.width = inst->prop.width;
frame_sz.height = inst->prop.height;
- pr_debug("width = %d, height = %d\n",
- frame_sz.width, frame_sz.height);
+ dprintk(VIDC_DBG,
+ "width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
rc = vidc_hal_session_set_property((void *)inst->session,
HAL_PARAM_FRAME_SIZE, &frame_sz);
if (rc) {
- pr_err("Failed to set hal property for framesize\n");
+ dprintk(VIDC_ERR,
+ "Failed to set hal property for framesize\n");
goto err_invalid_fmt;
}
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -512,8 +528,9 @@
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
OUTPUT_PORT);
if (fmt && fmt->type != OUTPUT_PORT) {
- pr_err("Format: %d not supported on OUTPUT port\n",
- f->fmt.pix_mp.pixelformat);
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto err_invalid_fmt;
}
@@ -530,13 +547,13 @@
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
if (rc) {
- pr_err("Failed to open instance\n");
+ dprintk(VIDC_ERR, "Failed to open instance\n");
goto err_invalid_fmt;
}
}
} else {
- pr_err("Buf type not recognized, type = %d\n",
- f->type);
+ dprintk(VIDC_ERR,
+ "Buf type not recognized, type = %d\n", f->type);
rc = -EINVAL;
}
err_invalid_fmt:
@@ -546,7 +563,8 @@
int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
{
if (!inst || !cap) {
- pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, cap = %p\n", inst, cap);
return -EINVAL;
}
strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
@@ -565,7 +583,8 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
if (!inst || !f) {
- pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, f = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -583,7 +602,7 @@
sizeof(f->description));
f->pixelformat = fmt->fourcc;
} else {
- pr_err("No more formats found\n");
+ dprintk(VIDC_WARN, "No more formats found\n");
rc = -EINVAL;
}
return rc;
@@ -600,7 +619,7 @@
unsigned long flags;
struct hal_buffer_requirements *bufreq;
if (!q || !q->drv_priv) {
- pr_err("Invalid input, q = %p\n", q);
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
@@ -616,16 +635,16 @@
}
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- pr_debug("Getting bufreqs on capture plane\n");
+ dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
- pr_err("Failed to open instance\n");
+ dprintk(VIDC_ERR, "Failed to open instance\n");
break;
}
-
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
- pr_err("Failed to get buffer requirements: %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Failed to get buffer requirements: %d\n", rc);
break;
}
*num_planes = 1;
@@ -649,8 +668,7 @@
else
bufreq->buffer_count_actual = *num_buffers ;
spin_unlock_irqrestore(&inst->lock, flags);
-
- pr_debug("count = %d, size = %d, alignment = %d\n",
+ dprintk(VIDC_DBG, "count = %d, size = %d, alignment = %d\n",
inst->buff_req.buffer[1].buffer_count_actual,
inst->buff_req.buffer[1].buffer_size,
inst->buff_req.buffer[1].buffer_alignment);
@@ -661,7 +679,7 @@
break;
default:
- pr_err("Invalid q type = %d\n", q->type);
+ dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
rc = -EINVAL;
break;
}
@@ -677,21 +695,25 @@
inst->in_reconfig = false;
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
- pr_err("Failed to set scratch buffers: %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Failed to set scratch buffers: %d\n", rc);
goto fail_start;
}
rc = msm_comm_set_persist_buffers(inst);
if (rc) {
- pr_err("Failed to set persist buffers: %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type))
- pr_warn("Failed to scale clocks. Performance might be impacted\n");
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Performance might be impacted\n");
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
- pr_err("Failed to move inst: %p to start done state\n",
- inst);
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
goto fail_start;
}
@@ -701,7 +723,8 @@
temp = list_entry(ptr, struct vb2_buf_entry, list);
rc = msm_comm_qbuf(temp->vb);
if (rc) {
- pr_err("Failed to qbuf to hardware\n");
+ dprintk(VIDC_ERR,
+ "Failed to qbuf to hardware\n");
break;
}
list_del(&temp->list);
@@ -719,11 +742,12 @@
struct msm_vidc_inst *inst;
int rc = 0;
if (!q || !q->drv_priv) {
- pr_err("Invalid input, q = %p\n", q);
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
- pr_debug("Streamon called on: %d capability\n", q->type);
+ dprintk(VIDC_DBG,
+ "Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (inst->vb2_bufq[CAPTURE_PORT].streaming)
@@ -734,7 +758,7 @@
rc = start_streaming(inst);
break;
default:
- pr_err("Q-type is not supported: %d\n", q->type);
+ dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
rc = -EINVAL;
break;
}
@@ -746,11 +770,11 @@
struct msm_vidc_inst *inst;
int rc = 0;
if (!q || !q->drv_priv) {
- pr_err("Invalid input, q = %p\n", q);
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
- pr_debug("Streamoff called on: %d capability\n", q->type);
+ dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
@@ -763,16 +787,20 @@
MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
default:
- pr_err("Q-type is not supported: %d\n", q->type);
+ dprintk(VIDC_ERR,
+ "Q-type is not supported: %d\n", q->type);
rc = -EINVAL;
break;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type))
- pr_warn("Failed to scale clocks. Power might be impacted\n");
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Power might be impacted\n");
+ }
if (rc)
- pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
- inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
return rc;
}
@@ -781,7 +809,7 @@
int rc;
rc = msm_comm_qbuf(vb);
if (rc)
- pr_err("Failed to queue buffer: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
}
int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
@@ -795,12 +823,12 @@
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
break;
default:
- pr_err("Unknown Decoder Command\n");
+ dprintk(VIDC_ERR, "Unknown Decoder Command\n");
rc = -ENOTSUPP;
goto exit;
}
if (rc) {
- pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
+ dprintk(VIDC_ERR, "Failed to exec decoder cmd %d\n", dec->cmd);
goto exit;
}
exit:
@@ -824,7 +852,7 @@
{
int rc = 0;
if (!inst) {
- pr_err("Invalid input = %p\n", inst);
+ dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
return -EINVAL;
}
inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
@@ -851,8 +879,8 @@
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
- pr_err("Failed to move inst: %p to start done state\n",
- inst);
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
goto failed_open_done;
}
@@ -911,16 +939,17 @@
break;
}
if (property_id) {
- pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
- property_id,
- msm_vdec_ctrls[control_idx].id,
- control.value);
+ dprintk(VIDC_DBG,
+ "Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ property_id,
+ msm_vdec_ctrls[control_idx].id,
+ control.value);
rc = vidc_hal_session_set_property((void *)
inst->session, property_id,
pdata);
}
if (rc)
- pr_err("Failed to set hal property for framesize\n");
+ dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
failed_open_done:
@@ -959,7 +988,7 @@
ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
if (ret_val) {
- pr_err("CTRL ERR: Control handler init failed, %d\n",
+ dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
inst->ctrl_handler.error);
return ret_val;
}
@@ -1007,7 +1036,8 @@
}
ret_val = inst->ctrl_handler.error;
if (ret_val)
- pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
- inst->ctrl_handler.error);
+ dprintk(VIDC_ERR,
+ "Error adding ctrls to ctrl handle, %d\n",
+ inst->ctrl_handler.error);
return ret_val;
}
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 2564a55..20493be 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -16,6 +16,7 @@
#include "msm_vidc_common.h"
#include "vidc_hal_api.h"
#include "msm_smem.h"
+#include "msm_vidc_debug.h"
#define MSM_VENC_DVC_NAME "msm_venc_8974"
#define DEFAULT_HEIGHT 720
@@ -565,7 +566,7 @@
struct hal_frame_size frame_sz;
unsigned long flags;
if (!q || !q->drv_priv) {
- pr_err("Invalid input, q = %p\n", q);
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
@@ -583,37 +584,40 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
- pr_err("Failed to open instance\n");
+ dprintk(VIDC_ERR, "Failed to open instance\n");
break;
}
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->prop.width;
frame_sz.height = inst->prop.height;
- pr_debug("width = %d, height = %d\n",
+ dprintk(VIDC_DBG, "width = %d, height = %d\n",
frame_sz.width, frame_sz.height);
rc = vidc_hal_session_set_property((void *)inst->session,
HAL_PARAM_FRAME_SIZE, &frame_sz);
if (rc) {
- pr_err("Failed to set framesize for Output port\n");
+ dprintk(VIDC_ERR,
+ "Failed to set framesize for Output port\n");
break;
}
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
rc = vidc_hal_session_set_property((void *)inst->session,
HAL_PARAM_FRAME_SIZE, &frame_sz);
if (rc) {
- pr_err("Failed to set framesize for Capture port\n");
+ dprintk(VIDC_ERR,
+ "Failed to set hal property for framesize\n");
break;
}
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
- pr_err("Failed to get buffer requirements: %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Failed to get buffer requirements: %d\n", rc);
break;
}
*num_planes = 1;
spin_lock_irqsave(&inst->lock, flags);
*num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
spin_unlock_irqrestore(&inst->lock, flags);
- pr_debug("size = %d, alignment = %d, count = %d\n",
+ dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
inst->buff_req.buffer[0].buffer_size,
inst->buff_req.buffer[0].buffer_alignment,
inst->buff_req.buffer[0].buffer_count_actual);
@@ -624,7 +628,7 @@
break;
default:
- pr_err("Invalid q type = %d\n", q->type);
+ dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
rc = -EINVAL;
break;
}
@@ -639,26 +643,29 @@
struct list_head *ptr, *next;
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
- pr_err("Failed to get Buffer Requirements : %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Failed to get Buffer Requirements : %d\n", rc);
goto fail_start;
}
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
- pr_err("Failed to set scratch buffers: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc);
goto fail_start;
}
rc = msm_comm_set_persist_buffers(inst);
if (rc) {
- pr_err("Failed to set persist buffers: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type))
- pr_warn("Failed to scale clocks. Performance might be impacted\n");
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Performance might be impacted\n");
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
- pr_err("Failed to move inst: %p to start done state\n",
- inst);
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
goto fail_start;
}
spin_lock_irqsave(&inst->lock, flags);
@@ -667,7 +674,8 @@
temp = list_entry(ptr, struct vb2_buf_entry, list);
rc = msm_comm_qbuf(temp->vb);
if (rc) {
- pr_err("Failed to qbuf to hardware\n");
+ dprintk(VIDC_ERR,
+ "Failed to qbuf to hardware\n");
break;
}
list_del(&temp->list);
@@ -685,11 +693,11 @@
struct msm_vidc_inst *inst;
int rc = 0;
if (!q || !q->drv_priv) {
- pr_err("Invalid input, q = %p\n", q);
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
- pr_debug("Streamon called on: %d capability\n", q->type);
+ dprintk(VIDC_DBG, "Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (inst->vb2_bufq[CAPTURE_PORT].streaming)
@@ -700,7 +708,7 @@
rc = start_streaming(inst);
break;
default:
- pr_err("Q-type is not supported: %d\n", q->type);
+ dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
rc = -EINVAL;
break;
}
@@ -712,11 +720,11 @@
struct msm_vidc_inst *inst;
int rc = 0;
if (!q || !q->drv_priv) {
- pr_err("Invalid input, q = %p\n", q);
+ dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
- pr_debug("Streamoff called on: %d capability\n", q->type);
+ dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
@@ -724,16 +732,19 @@
rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
default:
- pr_err("Q-type is not supported: %d\n", q->type);
+ dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
rc = -EINVAL;
break;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type))
- pr_warn("Failed to scale clocks. Power might be impacted\n");
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Power might be impacted\n");
+ }
if (rc)
- pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
- inst, q->type, MSM_VIDC_CLOSE_DONE);
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
return rc;
}
@@ -742,7 +753,7 @@
int rc;
rc = msm_comm_qbuf(vb);
if (rc)
- pr_err("Failed to queue buffer: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
}
static const struct vb2_ops msm_venc_vb2q_ops = {
@@ -774,7 +785,6 @@
struct hal_intra_refresh intra_refresh;
struct hal_multi_slice_control multi_slice_control;
struct hal_h264_db_control h264_db_control;
- u32 control_idx = 0;
u32 property_id = 0;
u32 property_val = 0;
void *pdata;
@@ -782,8 +792,8 @@
struct msm_vidc_inst, ctrl_handler);
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
- pr_err("Failed to move inst: %p to start done state\n",
- inst);
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
goto failed_open_done;
}
control.id = ctrl->id;
@@ -939,7 +949,7 @@
venc_h264_profile_level.profile = control.value;
profile_level.level = venc_h264_profile_level.level;
pdata = &profile_level;
- pr_debug("\nprofile: %d\n",
+ dprintk(VIDC_DBG, "\nprofile: %d\n",
profile_level.profile);
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
@@ -1003,7 +1013,7 @@
profile_level.profile = venc_h264_profile_level.profile;
pdata = &profile_level;
pdata = &profile_level;
- pr_debug("\nLevel: %d\n",
+ dprintk(VIDC_DBG, "\nLevel: %d\n",
profile_level.level);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
@@ -1187,24 +1197,25 @@
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
h264_db_control.slice_alpha_offset = control.value;
pdata = &h264_db_control;
+ break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
property_id =
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
h264_db_control.slice_beta_offset = control.value;
pdata = &h264_db_control;
+ break;
default:
break;
}
if (property_id) {
- pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ dprintk(VIDC_DBG, "Control: HAL property=%d,ctrl_value=%d\n",
property_id,
- msm_venc_ctrls[control_idx].id,
control.value);
rc = vidc_hal_session_set_property((void *)inst->session,
property_id, pdata);
}
if (rc)
- pr_err("Failed to set hal property for framesize\n");
+ dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
failed_open_done:
return rc;
}
@@ -1228,7 +1239,7 @@
{
int rc = 0;
if (!inst) {
- pr_err("Invalid input = %p\n", inst);
+ dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
return -EINVAL;
}
inst->fmts[CAPTURE_PORT] = &venc_formats[1];
@@ -1260,14 +1271,16 @@
break;
}
if (rc)
- pr_err("Command: %d failed with rc = %d\n", enc->cmd, rc);
+ dprintk(VIDC_ERR,
+ "Command: %d failed with rc = %d\n", enc->cmd, rc);
return rc;
}
int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
{
if (!inst || !cap) {
- pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, cap = %p\n", inst, cap);
return -EINVAL;
}
strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
@@ -1286,7 +1299,8 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
if (!inst || !f) {
- pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, f = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -1304,7 +1318,7 @@
sizeof(f->description));
f->pixelformat = fmt->fourcc;
} else {
- pr_err("No more formats found\n");
+ dprintk(VIDC_ERR, "No more formats found\n");
rc = -EINVAL;
}
return rc;
@@ -1316,7 +1330,8 @@
int rc = 0;
int i;
if (!inst || !f) {
- pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -1324,8 +1339,9 @@
ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
CAPTURE_PORT);
if (fmt && fmt->type != CAPTURE_PORT) {
- pr_err("Format: %d not supported on CAPTURE port\n",
- f->fmt.pix_mp.pixelformat);
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto exit;
}
@@ -1336,8 +1352,9 @@
ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
OUTPUT_PORT);
if (fmt && fmt->type != OUTPUT_PORT) {
- pr_err("Format: %d not supported on OUTPUT port\n",
- f->fmt.pix_mp.pixelformat);
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto exit;
}
@@ -1354,12 +1371,12 @@
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
- pr_err("Failed to open instance\n");
+ dprintk(VIDC_ERR, "Failed to open instance\n");
goto exit;
}
}
} else {
- pr_err("Buf type not recognized, type = %d\n",
+ dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
f->type);
rc = -EINVAL;
}
@@ -1373,7 +1390,8 @@
int rc = 0;
int i;
if (!inst || !f) {
- pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -1392,8 +1410,8 @@
inst->prop.width);
}
} else {
- pr_err("Buf type not recognized, type = %d\n",
- f->type);
+ dprintk(VIDC_ERR,
+ "Buf type not recognized, type = %d\n", f->type);
rc = -EINVAL;
}
return rc;
@@ -1404,18 +1422,20 @@
struct vb2_queue *q = NULL;
int rc = 0;
if (!inst || !b) {
- pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ dprintk(VIDC_ERR,
+ "Invalid input, inst = %p, buffer = %p\n", inst, b);
return -EINVAL;
}
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", b->type);
return -EINVAL;
}
rc = vb2_reqbufs(q, b);
if (rc)
- pr_err("Failed to get reqbufs, %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
return rc;
}
@@ -1431,7 +1451,8 @@
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
for (i = 0; i < b->length; i++) {
- pr_debug("device_addr = %ld, size = %d\n",
+ dprintk(VIDC_DBG,
+ "device_addr = %ld, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
buffer_info.buffer_size = b->m.planes[i].length;
@@ -1444,11 +1465,13 @@
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
if (rc)
- pr_err("vidc_hal_session_set_buffers failed");
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed");
}
break;
default:
- pr_err("Buffer type not recognized: %d\n", b->type);
+ dprintk(VIDC_ERR,
+ "Buffer type not recognized: %d\n", b->type);
break;
}
return rc;
@@ -1460,12 +1483,13 @@
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", b->type);
return -EINVAL;
}
rc = vb2_qbuf(q, b);
if (rc)
- pr_err("Failed to qbuf, %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
return rc;
}
@@ -1475,12 +1499,13 @@
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", b->type);
return -EINVAL;
}
rc = vb2_dqbuf(q, b, true);
if (rc)
- pr_err("Failed to dqbuf, %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
return rc;
}
@@ -1490,13 +1515,14 @@
struct vb2_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", i);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
return -EINVAL;
}
- pr_debug("Calling streamon\n");
+ dprintk(VIDC_DBG, "Calling streamon\n");
rc = vb2_streamon(q, i);
if (rc)
- pr_err("streamon failed on port: %d\n", i);
+ dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
return rc;
}
@@ -1506,13 +1532,14 @@
struct vb2_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
- pr_err("Failed to find buffer queue for type = %d\n", i);
+ dprintk(VIDC_ERR,
+ "Failed to find buffer queue for type = %d\n", i);
return -EINVAL;
}
- pr_debug("Calling streamoff\n");
+ dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
rc = vb2_streamoff(q, i);
if (rc)
- pr_err("streamoff failed on port: %d\n", i);
+ dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
return rc;
}
@@ -1524,7 +1551,7 @@
int ret_val = 0;
ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
if (ret_val) {
- pr_err("CTRL ERR: Control handler init failed, %d\n",
+ dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
inst->ctrl_handler.error);
return ret_val;
}
@@ -1566,7 +1593,8 @@
}
ret_val = inst->ctrl_handler.error;
if (ret_val)
- pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
- inst->ctrl_handler.error);
+ dprintk(VIDC_ERR,
+ "CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+ inst->ctrl_handler.error);
return ret_val;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 7c9b6db..449dab2 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -14,10 +14,12 @@
#include <linux/slab.h>
#include <media/msm_vidc.h>
#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
#include "msm_vdec.h"
#include "msm_venc.h"
#include "msm_vidc_common.h"
#include "msm_smem.h"
+#include <linux/delay.h>
int msm_vidc_poll(void *instance, struct file *filp,
struct poll_table_struct *wait)
@@ -215,7 +217,7 @@
} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
q = &inst->vb2_bufq[OUTPUT_PORT];
} else {
- pr_err("buf_type = %d not recognised\n", type);
+ dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
return -EINVAL;
}
q->type = type;
@@ -239,13 +241,14 @@
int i = 0;
if (core_id >= MSM_VIDC_CORES_MAX ||
session_type >= MSM_VIDC_MAX_DEVICES) {
- pr_err("Invalid input, core_id = %d, session = %d\n",
+ dprintk(VIDC_ERR, "Invalid input, core_id = %d, session = %d\n",
core_id, session_type);
goto err_invalid_core;
}
core = get_vidc_core(core_id);
if (!core) {
- pr_err("Failed to find core for core_id = %d\n", core_id);
+ dprintk(VIDC_ERR,
+ "Failed to find core for core_id = %d\n", core_id);
goto err_invalid_core;
}
@@ -263,7 +266,7 @@
}
inst->mem_client = msm_smem_new_client(SMEM_ION);
if (!inst->mem_client) {
- pr_err("Failed to create memory client\n");
+ dprintk(VIDC_ERR, "Failed to create memory client\n");
goto fail_mem_client;
}
if (session_type == MSM_VIDC_DECODER) {
@@ -276,20 +279,25 @@
rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
session_type);
if (rc) {
- pr_err("Failed to initialize vb2 queue on capture port\n");
+ dprintk(VIDC_ERR,
+ "Failed to initialize vb2 queue on capture port\n");
goto fail_init;
}
rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
session_type);
if (rc) {
- pr_err("Failed to initialize vb2 queue on capture port\n");
+ dprintk(VIDC_ERR,
+ "Failed to initialize vb2 queue on capture port\n");
goto fail_init;
}
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
if (rc) {
- pr_err("Failed to move video instance to init state\n");
+ dprintk(VIDC_ERR,
+ "Failed to move video instance to init state\n");
goto fail_init;
}
+ inst->debugfs_root =
+ msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
spin_lock_irqsave(&core->lock, flags);
list_add_tail(&inst->list, &core->instances);
spin_unlock_irqrestore(&core->lock, flags);
@@ -341,6 +349,7 @@
msm_smem_free(inst->mem_client, inst->extradata_handle);
spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_delete_client(inst->mem_client);
+ debugfs_remove_recursive(inst->debugfs_root);
}
}
@@ -361,8 +370,9 @@
mutex_unlock(&core->sync_lock);
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
if (rc)
- pr_err("Failed to move video instance to uninit state\n");
+ dprintk(VIDC_ERR,
+ "Failed to move video instance to uninit state\n");
cleanup_instance(inst);
- pr_debug("Closed the instance\n");
+ dprintk(VIDC_DBG, "Closed the instance\n");
return 0;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index d85273d..ffe8c98 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -22,6 +22,7 @@
#include "msm_vidc_common.h"
#include "vidc_hal_api.h"
#include "msm_smem.h"
+#include "msm_vidc_debug.h"
#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
@@ -66,7 +67,7 @@
if (load >= bus_table[i])
break;
}
- pr_debug("Required bus = %d\n", i);
+ dprintk(VIDC_DBG, "Required bus = %d\n", i);
return i;
}
@@ -77,7 +78,7 @@
int num_mbs_per_sec = 0;
unsigned long flags;
if (!core) {
- pr_err("Invalid args: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid args: %p\n", core);
return -EINVAL;
}
list_for_each_entry(inst, &core->instances, list) {
@@ -105,7 +106,7 @@
break;
ret = table[i].freq;
}
- pr_debug("Required clock rate = %lu\n", ret);
+ dprintk(VIDC_INFO, "Required clock rate = %lu\n", ret);
return ret;
}
@@ -114,7 +115,7 @@
int load;
int rc = 0;
if (!core || type >= MSM_VIDC_MAX_DEVICES) {
- pr_err("Invalid args: %p, %d\n", core, type);
+ dprintk(VIDC_ERR, "Invalid args: %p, %d\n", core, type);
return -EINVAL;
}
load = msm_comm_get_load(core, type);
@@ -122,14 +123,14 @@
core->resources.bus_info.ddr_handle[type],
get_bus_vector(load));
if (rc) {
- pr_err("Failed to scale bus: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
goto fail_scale_bus;
}
rc = msm_bus_scale_client_update_request(
core->resources.bus_info.ocmem_handle[type],
get_bus_vector(load));
if (rc) {
- pr_err("Failed to scale bus: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
goto fail_scale_bus;
}
fail_scale_bus:
@@ -142,7 +143,7 @@
int found = 0;
unsigned long flags;
if (core_id > MSM_VIDC_CORES_MAX) {
- pr_err("Core id = %d is greater than max = %d\n",
+ dprintk(VIDC_ERR, "Core id = %d is greater than max = %d\n",
core_id, MSM_VIDC_CORES_MAX);
return NULL;
}
@@ -170,13 +171,15 @@
dev = msm_iommu_get_ctx(io_map->ctx);
domain = msm_get_iommu_domain(io_map->domain);
if (IS_ERR_OR_NULL(domain)) {
- pr_err("Failed to get domain: %s\n", io_map->name);
+ dprintk(VIDC_ERR,
+ "Failed to get domain: %s\n", io_map->name);
rc = PTR_ERR(domain);
break;
}
rc = iommu_attach_device(domain, dev);
if (rc) {
- pr_err("IOMMU attach failed: %s\n", io_map->name);
+ dprintk(VIDC_ERR,
+ "IOMMU attach failed: %s\n", io_map->name);
break;
}
}
@@ -200,7 +203,7 @@
struct iommu_info *io_map;
int i;
if (!core) {
- pr_err("Invalid paramter: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
return;
}
for (i = 0; i < MAX_MAP; i++) {
@@ -217,7 +220,7 @@
{
int i, k = 0;
if (!fmt || index < 0) {
- pr_err("Invalid inputs, fmt = %p, index = %d\n",
+ dprintk(VIDC_ERR, "Invalid inputs, fmt = %p, index = %d\n",
fmt, index);
return NULL;
}
@@ -229,7 +232,7 @@
k++;
}
if (i == size) {
- pr_err("Format not found\n");
+ dprintk(VIDC_WARN, "Format not found\n");
return NULL;
}
return &fmt[i];
@@ -239,7 +242,7 @@
{
int i;
if (!fmt) {
- pr_err("Invalid inputs, fmt = %p\n", fmt);
+ dprintk(VIDC_ERR, "Invalid inputs, fmt = %p\n", fmt);
return NULL;
}
for (i = 0; i < size; i++) {
@@ -247,7 +250,7 @@
break;
}
if (i == size) {
- pr_err("Format not found\n");
+ dprintk(VIDC_WARN, "Format not found\n");
return NULL;
}
return &fmt[i];
@@ -270,20 +273,21 @@
struct vidc_hal_sys_init_done *sys_init_msg;
int index = SYS_MSG_INDEX(cmd);
if (!response) {
- pr_err("Failed to get valid response for sys init\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for sys init\n");
return;
}
core = get_vidc_core(response->device_id);
if (!core) {
- pr_err("Wrong device_id received\n");
+ dprintk(VIDC_ERR, "Wrong device_id received\n");
return;
}
- pr_debug("index = %d\n", index);
- pr_debug("ptr = %p\n", &(core->completions[index]));
+ dprintk(VIDC_DBG, "index = %d\n", index);
+ dprintk(VIDC_DBG, "ptr = %p\n", &(core->completions[index]));
complete(&(core->completions[index]));
sys_init_msg = response->data;
if (!sys_init_msg) {
- pr_err("sys_init_done message not proper\n");
+ dprintk(VIDC_ERR, "sys_init_done message not proper\n");
return;
}
}
@@ -294,12 +298,13 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_core *core;
if (!response) {
- pr_err("Failed to get valid response for sys init\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for sys init\n");
return;
}
core = get_vidc_core(response->device_id);
if (!core) {
- pr_err("Wrong device_id received\n");
+ dprintk(VIDC_ERR, "Wrong device_id received\n");
return;
}
complete(&core->completions[SYS_MSG_INDEX(cmd)]);
@@ -310,7 +315,7 @@
{
unsigned long flags;
spin_lock_irqsave(&inst->lock, flags);
- pr_debug("Moved inst: %p from state: %d to state: %d\n",
+ dprintk(VIDC_DBG, "Moved inst: %p from state: %d to state: %d\n",
inst, inst->state, state);
inst->state = state;
spin_unlock_irqrestore(&inst->lock, flags);
@@ -320,7 +325,7 @@
struct msm_vidc_inst *inst)
{
if (!inst) {
- pr_err("Invalid(%p) instance id\n", inst);
+ dprintk(VIDC_ERR, "Invalid(%p) instance id\n", inst);
return -EINVAL;
}
complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
@@ -335,7 +340,7 @@
&inst->completions[SESSION_MSG_INDEX(cmd)],
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
- pr_err("Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
rc = -EIO;
} else {
rc = 0;
@@ -350,10 +355,11 @@
{
int rc = 0;
if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto err_same_state;
}
- pr_debug("Waiting for hal_cmd: %d\n", hal_cmd);
+ dprintk(VIDC_DBG, "Waiting for hal_cmd: %d\n", hal_cmd);
rc = wait_for_sess_signal_receipt(inst, hal_cmd);
if (!rc)
change_inst_state(inst, desired_state);
@@ -369,7 +375,8 @@
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
} else {
- pr_err("Failed to get valid response for session init\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for session init\n");
}
}
@@ -401,7 +408,8 @@
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
return;
} else {
- pr_err("Failed to get valid response for event_change\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for event_change\n");
}
}
@@ -412,7 +420,8 @@
unsigned long flags;
int i;
if (!response || !response->data) {
- pr_err("Failed to get valid response for prop info\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for prop info\n");
return;
}
inst = (struct msm_vidc_inst *)response->session_id;
@@ -421,7 +430,8 @@
sizeof(struct buffer_requirements));
spin_unlock_irqrestore(&inst->lock, flags);
for (i = 0; i < 8; i++) {
- pr_err("NOTE: buffer type: %d, count : %d, size: %d\n",
+ dprintk(VIDC_DBG,
+ "buffer type: %d, count : %d, size: %d\n",
inst->buff_req.buffer[i].buffer_type,
inst->buff_req.buffer[i].buffer_count_actual,
inst->buff_req.buffer[i].buffer_size);
@@ -436,7 +446,8 @@
if (response)
inst = (struct msm_vidc_inst *)response->session_id;
else
- pr_err("Failed to get valid response for load resource\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for load resource\n");
}
static void handle_start_done(enum command_response cmd, void *data)
@@ -447,7 +458,8 @@
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
} else {
- pr_err("Failed to get valid response for start\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for start\n");
}
}
@@ -459,7 +471,8 @@
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
} else {
- pr_err("Failed to get valid response for stop\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for stop\n");
}
}
@@ -471,7 +484,8 @@
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
} else {
- pr_err("Failed to get valid response for release resource\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for release resource\n");
}
}
@@ -486,7 +500,7 @@
dqevent.id = 0;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
} else {
- pr_err("Failed to get valid response for flush\n");
+ dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
}
}
@@ -503,7 +517,8 @@
dqevent.id = 0;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
} else {
- pr_err("Failed to get valid response for session close\n");
+ dprintk(VIDC_ERR,
+ "Failed to get valid response for session close\n");
}
}
@@ -513,7 +528,7 @@
struct vb2_buffer *vb = NULL;
int found = 0;
if (!q) {
- pr_err("Invalid parameter\n");
+ dprintk(VIDC_ERR, "Invalid parameter\n");
return NULL;
}
list_for_each_entry(vb, &q->queued_list, queued_entry) {
@@ -523,7 +538,8 @@
}
}
if (!found) {
- pr_err("Failed to find the buffer in queued list: %d, %d\n",
+ dprintk(VIDC_ERR,
+ "Failed to find the buffer in queued list: %d, %d\n",
dev_addr, q->type);
vb = NULL;
}
@@ -535,7 +551,7 @@
struct msm_vidc_cb_data_done *response = data;
struct vb2_buffer *vb;
if (!response) {
- pr_err("Invalid response from vidc_hal\n");
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
return;
}
vb = response->clnt_data;
@@ -550,7 +566,7 @@
struct vb2_buffer *vb;
struct vidc_hal_fbd *fill_buf_done;
if (!response) {
- pr_err("Invalid response from vidc_hal\n");
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
return;
}
inst = (struct msm_vidc_inst *)response->session_id;
@@ -569,9 +585,16 @@
vb->v4l2_buf.timestamp =
ns_to_timeval(time_usec * NSEC_PER_USEC);
}
+ vb->v4l2_buf.flags = 0;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+ vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
+ if (!inst->fbd_count)
+ vb->v4l2_buf.flags = V4L2_BUF_FLAG_KEYFRAME;
+ ++inst->fbd_count;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
@@ -589,9 +612,11 @@
/* Do we need to care about these? */
case HAL_FRAME_YUV:
break;
+ default:
+ break;
}
- pr_debug("Filled length = %d; flags %x\n",
+ dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
vb->v4l2_planes[0].bytesused,
vb->v4l2_buf.flags);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -625,9 +650,34 @@
}
}
+static void handle_seq_hdr_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct vb2_buffer *vb;
+ struct vidc_hal_fbd *fill_buf_done;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+ vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+ (u32)fill_buf_done->packet_buffer1);
+ if (vb)
+ vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+
+ vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
+ dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+ vb->v4l2_planes[0].bytesused,
+ vb->v4l2_buf.flags);
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
void handle_cmd_response(enum command_response cmd, void *data)
{
- pr_debug("Command response = %d\n", cmd);
+ dprintk(VIDC_DBG, "Command response = %d\n", cmd);
switch (cmd) {
case SYS_INIT_DONE:
handle_sys_init_done(cmd, data);
@@ -668,8 +718,11 @@
case SESSION_FLUSH_DONE:
handle_session_flush(cmd, data);
break;
+ case SESSION_GET_SEQ_HDR_DONE:
+ handle_seq_hdr_done(cmd, data);
+ break;
default:
- pr_err("response unhandled\n");
+ dprintk(VIDC_ERR, "response unhandled\n");
break;
}
}
@@ -679,22 +732,22 @@
int num_mbs_per_sec;
int rc = 0;
if (!core) {
- pr_err("Invalid args: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid args: %p\n", core);
return -EINVAL;
}
num_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_ENCODER);
num_mbs_per_sec += msm_comm_get_load(core, MSM_VIDC_DECODER);
- pr_debug("num_mbs_per_sec = %d\n", num_mbs_per_sec);
+ dprintk(VIDC_INFO, "num_mbs_per_sec = %d\n", num_mbs_per_sec);
rc = clk_set_rate(core->resources.clock[VCODEC_CLK].clk,
get_clock_rate(&core->resources.clock[VCODEC_CLK],
num_mbs_per_sec));
if (rc) {
- pr_err("Failed to set clock rate: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
goto fail_clk_set_rate;
}
rc = msm_comm_scale_bus(core, type);
if (rc)
- pr_err("Failed to scale bus bandwidth\n");
+ dprintk(VIDC_ERR, "Failed to scale bus bandwidth\n");
fail_clk_set_rate:
return rc;
}
@@ -705,17 +758,17 @@
struct core_clock *cl;
int rc = 0;
if (!core) {
- pr_err("Invalid params: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid params: %p\n", core);
return -EINVAL;
}
for (i = 0; i < VCODEC_MAX_CLKS; i++) {
cl = &core->resources.clock[i];
rc = clk_prepare_enable(cl->clk);
if (rc) {
- pr_err("Failed to enable clocks\n");
+ dprintk(VIDC_ERR, "Failed to enable clocks\n");
goto fail_clk_enable;
} else {
- pr_err("Clock: %s enabled\n", cl->name);
+ dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
}
}
return rc;
@@ -732,7 +785,7 @@
int i;
struct core_clock *cl;
if (!core) {
- pr_err("Invalid params: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid params: %p\n", core);
return;
}
for (i = 0; i < VCODEC_MAX_CLKS; i++) {
@@ -745,7 +798,7 @@
{
int rc = 0;
if (!core) {
- pr_err("Invalid paramter: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
return -EINVAL;
}
@@ -753,20 +806,20 @@
core->resources.fw.cookie = pil_get("venus");
if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
- pr_err("Failed to download firmware\n");
+ dprintk(VIDC_ERR, "Failed to download firmware\n");
rc = -ENOMEM;
goto fail_pil_get;
}
rc = msm_comm_enable_clks(core);
if (rc) {
- pr_err("Failed to enable clocks: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
goto fail_enable_clks;
}
rc = msm_comm_iommu_attach(core);
if (rc) {
- pr_err("Failed to attach iommu");
+ dprintk(VIDC_ERR, "Failed to attach iommu");
goto fail_iommu_attach;
}
return rc;
@@ -782,7 +835,7 @@
static void msm_comm_unload_fw(struct msm_vidc_core *core)
{
if (!core) {
- pr_err("Invalid paramter: %p\n", core);
+ dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
return;
}
if (core->resources.fw.cookie) {
@@ -808,7 +861,7 @@
struct vidc_resource_hdr rhdr;
int rc = 0;
if (!core || !ocmem) {
- pr_err("Invalid params, core:%p, ocmem: %p\n",
+ dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
core, ocmem);
return -EINVAL;
}
@@ -817,10 +870,10 @@
rhdr.size = ocmem->len;
rc = vidc_hal_core_set_resource(core->device, &rhdr, ocmem);
if (rc) {
- pr_err("Failed to set OCMEM on driver\n");
+ dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
goto ocmem_set_failed;
}
- pr_debug("OCMEM set, addr = %lx, size: %ld\n",
+ dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
ocmem->addr, ocmem->len);
ocmem_set_failed:
return rc;
@@ -831,7 +884,7 @@
struct vidc_resource_hdr rhdr;
int rc = 0;
if (!core || !core->resources.ocmem.buf) {
- pr_err("Invalid params, core:%p\n", core);
+ dprintk(VIDC_ERR, "Invalid params, core:%p\n", core);
return -EINVAL;
}
rhdr.resource_id = VIDC_RESOURCE_OCMEM;
@@ -840,14 +893,14 @@
&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
rc = vidc_hal_core_release_resource(core->device, &rhdr);
if (rc) {
- pr_err("Failed to set OCMEM on driver\n");
+ dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
goto release_ocmem_failed;
}
rc = wait_for_completion_timeout(
&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
- pr_err("Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
rc = -EIO;
goto release_ocmem_failed;
}
@@ -862,7 +915,8 @@
unsigned long flags;
struct ocmem_buf *ocmem_buffer;
if (!core || !size) {
- pr_err("Invalid param, core: %p, size: %lu\n", core, size);
+ dprintk(VIDC_ERR,
+ "Invalid param, core: %p, size: %lu\n", core, size);
return -EINVAL;
}
spin_lock_irqsave(&core->lock, flags);
@@ -871,18 +925,20 @@
ocmem_buffer->len < size) {
ocmem_buffer = ocmem_allocate_nb(OCMEM_VIDEO, size);
if (IS_ERR_OR_NULL(ocmem_buffer)) {
- pr_err("ocmem_allocate_nb failed: %d\n",
+ dprintk(VIDC_ERR,
+ "ocmem_allocate_nb failed: %d\n",
(u32) ocmem_buffer);
rc = -ENOMEM;
}
core->resources.ocmem.buf = ocmem_buffer;
rc = msm_comm_set_ocmem(core, ocmem_buffer);
if (rc) {
- pr_err("Failed to set ocmem: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
goto ocmem_set_failed;
}
} else
- pr_debug("OCMEM is enough. reqd: %lu, available: %lu\n",
+ dprintk(VIDC_DBG,
+ "OCMEM is enough. reqd: %lu, available: %lu\n",
size, ocmem_buffer->len);
ocmem_set_failed:
@@ -898,7 +954,7 @@
if (core->resources.ocmem.buf) {
rc = ocmem_free(OCMEM_VIDEO, core->resources.ocmem.buf);
if (rc)
- pr_err("Failed to free ocmem\n");
+ dprintk(VIDC_ERR, "Failed to free ocmem\n");
}
core->resources.ocmem.buf = NULL;
spin_unlock_irqrestore(&core->lock, flags);
@@ -916,7 +972,7 @@
if (event == OCMEM_ALLOC_GROW) {
ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
if (!ocmem) {
- pr_err("Wrong handler passed\n");
+ dprintk(VIDC_ERR, "Wrong handler passed\n");
rc = NOTIFY_BAD;
goto bad_notfier;
}
@@ -925,7 +981,7 @@
core = container_of(resources,
struct msm_vidc_core, resources);
if (msm_comm_set_ocmem(core, buff)) {
- pr_err("Failed to set ocmem: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
goto ocmem_set_failed;
}
rc = NOTIFY_OK;
@@ -942,16 +998,16 @@
int rc = 0;
mutex_lock(&core->sync_lock);
if (core->state >= VIDC_CORE_INIT_DONE) {
- pr_err("Video core: %d is already in state: %d\n",
+ dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
core->id, core->state);
goto core_already_inited;
}
- pr_debug("Waiting for SYS_INIT_DONE\n");
+ dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
rc = wait_for_completion_timeout(
&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
- pr_err("Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
rc = -EIO;
goto exit;
} else {
@@ -959,7 +1015,7 @@
core->state = VIDC_CORE_INIT_DONE;
spin_unlock_irqrestore(&core->lock, flags);
}
- pr_debug("SYS_INIT_DONE!!!\n");
+ dprintk(VIDC_DBG, "SYS_INIT_DONE!!!\n");
core_already_inited:
change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
rc = 0;
@@ -975,25 +1031,25 @@
unsigned long flags;
mutex_lock(&core->sync_lock);
if (core->state >= VIDC_CORE_INIT) {
- pr_err("Video core: %d is already in state: %d\n",
+ dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
core->id, core->state);
goto core_already_inited;
}
rc = msm_comm_scale_clocks(core, inst->session_type);
if (rc) {
- pr_err("Failed to set clock rate: %d\n", rc);
+ dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
goto fail_load_fw;
}
rc = msm_comm_load_fw(core);
if (rc) {
- pr_err("Failed to load video firmware\n");
+ dprintk(VIDC_ERR, "Failed to load video firmware\n");
goto fail_load_fw;
}
init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
rc = vidc_hal_core_init(core->device,
core->resources.io_map[NS_MAP].domain);
if (rc) {
- pr_err("Failed to init core, id = %d\n", core->id);
+ dprintk(VIDC_ERR, "Failed to init core, id = %d\n", core->id);
goto fail_core_init;
}
spin_lock_irqsave(&core->lock, flags);
@@ -1017,20 +1073,22 @@
unsigned long flags;
mutex_lock(&core->sync_lock);
if (core->state == VIDC_CORE_UNINIT) {
- pr_err("Video core: %d is already in state: %d\n",
+ dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
core->id, core->state);
goto core_already_uninited;
}
if (msm_comm_scale_clocks(core, inst->session_type)) {
- pr_warn("Failed to scale clocks while closing\n");
- pr_warn("Power might be impacted\n");
+ dprintk(VIDC_WARN, "Failed to scale clocks while closing\n");
+ dprintk(VIDC_WARN, "Power might be impacted\n");
}
if (list_empty(&core->instances)) {
msm_comm_unset_ocmem(core);
msm_comm_free_ocmem(core);
+ dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
rc = vidc_hal_core_release(core->device);
if (rc) {
- pr_err("Failed to release core, id = %d\n", core->id);
+ dprintk(VIDC_ERR, "Failed to release core, id = %d\n",
+ core->id);
goto exit;
}
spin_lock_irqsave(&core->lock, flags);
@@ -1056,7 +1114,7 @@
domain = HAL_VIDEO_DOMAIN_DECODER;
break;
default:
- pr_err("Wrong domain\n");
+ dprintk(VIDC_ERR, "Wrong domain\n");
domain = HAL_UNUSED_DOMAIN;
break;
}
@@ -1066,7 +1124,7 @@
static enum hal_video_codec get_hal_codec_type(int fourcc)
{
enum hal_video_codec codec;
- pr_debug("codec in %s is 0x%x", __func__, fourcc);
+ dprintk(VIDC_DBG, "codec is 0x%x", fourcc);
switch (fourcc) {
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_H264_NO_SC:
@@ -1102,7 +1160,7 @@
HAL_VIDEO_CODEC_VP6
HAL_VIDEO_CODEC_VP7*/
default:
- pr_err("Wrong codec: %d\n", fourcc);
+ dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
}
return codec;
@@ -1114,7 +1172,8 @@
int rc = 0;
int fourcc = 0;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto exit;
}
if (inst->session_type == MSM_VIDC_DECODER) {
@@ -1122,7 +1181,7 @@
} else if (inst->session_type == MSM_VIDC_ENCODER) {
fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
} else {
- pr_err("Invalid session\n");
+ dprintk(VIDC_ERR, "Invalid session\n");
return -EINVAL;
}
init_completion(
@@ -1131,11 +1190,14 @@
get_hal_domain(inst->session_type),
get_hal_codec_type(fourcc));
if (!inst->session) {
- pr_err("Failed to call session init for: %d, %d, %d, %d\n",
- (int)inst->core->device, (int)inst,
- inst->session_type, fourcc);
+ dprintk(VIDC_ERR,
+ "Failed to call session init for: %d, %d, %d, %d\n",
+ (int)inst->core->device, (int)inst,
+ inst->session_type, fourcc);
goto exit;
}
+ inst->ftb_count = 0;
+ inst->fbd_count = 0;
change_inst_state(inst, MSM_VIDC_OPEN);
exit:
return rc;
@@ -1147,17 +1209,20 @@
int rc = 0;
u32 ocmem_sz = 0;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto exit;
}
ocmem_sz = get_ocmem_requirement(inst->prop.height, inst->prop.width);
rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
if (rc)
- pr_warn("Failed to allocate OCMEM. Performance will be impacted\n");
+ dprintk(VIDC_WARN,
+ "Failed to allocate OCMEM. Performance will be impacted\n");
rc = vidc_hal_session_load_res((void *) inst->session);
if (rc) {
- pr_err("Failed to send load resources\n");
+ dprintk(VIDC_ERR,
+ "Failed to send load resources\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
@@ -1169,14 +1234,17 @@
{
int rc = 0;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto exit;
}
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
rc = vidc_hal_session_start((void *) inst->session);
if (rc) {
- pr_err("Failed to send load resources\n");
+ dprintk(VIDC_ERR,
+ "Failed to send load resources\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_START);
@@ -1188,15 +1256,17 @@
{
int rc = 0;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto exit;
}
- pr_debug("Send Stop to hal\n");
+ dprintk(VIDC_DBG, "Send Stop to hal\n");
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
rc = vidc_hal_session_stop((void *) inst->session);
if (rc) {
- pr_err("Failed to send stop\n");
+ dprintk(VIDC_ERR, "Failed to send stop\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_STOP);
@@ -1208,15 +1278,19 @@
{
int rc = 0;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto exit;
}
- pr_debug("Send release res to hal\n");
+ dprintk(VIDC_DBG,
+ "Send release res to hal\n");
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
rc = vidc_hal_session_release_res((void *) inst->session);
if (rc) {
- pr_err("Failed to send load resources\n");
+ dprintk(VIDC_ERR,
+ "Failed to send load resources\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
@@ -1228,15 +1302,19 @@
{
int rc = 0;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
- pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ dprintk(VIDC_INFO,
+ "inst: %p is already in state: %d\n",
+ inst, inst->state);
goto exit;
}
- pr_debug("Send session close to hal\n");
+ dprintk(VIDC_DBG,
+ "Send session close to hal\n");
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
rc = vidc_hal_session_end((void *) inst->session);
if (rc) {
- pr_err("Failed to send load resources\n");
+ dprintk(VIDC_ERR,
+ "Failed to send load resources\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_OPEN);
@@ -1249,10 +1327,12 @@
int rc = 0;
int flipped_state;
if (!inst) {
- pr_err("Invalid instance pointer = %p\n", inst);
+ dprintk(VIDC_ERR,
+ "Invalid instance pointer = %p\n", inst);
return -EINVAL;
}
- pr_debug("Trying to move inst: %p from: 0x%x to 0x%x\n",
+ dprintk(VIDC_DBG,
+ "Trying to move inst: %p from: 0x%x to 0x%x\n",
inst, inst->state, state);
mutex_lock(&inst->sync_lock);
flipped_state = inst->state;
@@ -1268,7 +1348,8 @@
flipped_state &= 0xFFFE;
flipped_state = flipped_state - 1;
}
- pr_debug("flipped_state = 0x%x\n", flipped_state);
+ dprintk(VIDC_DBG,
+ "flipped_state = 0x%x\n", flipped_state);
switch (flipped_state) {
case MSM_VIDC_CORE_UNINIT_DONE:
case MSM_VIDC_CORE_INIT:
@@ -1311,7 +1392,7 @@
SESSION_STOP_DONE);
if (rc || state <= inst->state)
break;
- pr_debug("Moving to Stop Done state\n");
+ dprintk(VIDC_DBG, "Moving to Stop Done state\n");
case MSM_VIDC_RELEASE_RESOURCES:
rc = msm_vidc_release_res(flipped_state, inst);
if (rc || state <= inst->state)
@@ -1322,7 +1403,8 @@
SESSION_RELEASE_RESOURCE_DONE);
if (rc || state <= inst->state)
break;
- pr_debug("Moving to release resources done state\n");
+ dprintk(VIDC_DBG,
+ "Moving to release resources done state\n");
case MSM_VIDC_CLOSE:
rc = msm_comm_session_close(flipped_state, inst);
if (rc || state <= inst->state)
@@ -1333,18 +1415,19 @@
if (rc || state <= inst->state)
break;
case MSM_VIDC_CORE_UNINIT:
- pr_debug("***************Sending core uninit\n");
+ dprintk(VIDC_DBG, "Sending core uninit\n");
rc = msm_vidc_deinit_core(inst);
if (rc || state == inst->state)
break;
default:
- pr_err("State not recognized: %d\n", flipped_state);
+ dprintk(VIDC_ERR, "State not recognized\n");
rc = -EINVAL;
break;
}
mutex_unlock(&inst->sync_lock);
if (rc)
- pr_err("Failed to move from state: %d to %d\n",
+ dprintk(VIDC_ERR,
+ "Failed to move from state: %d to %d\n",
inst->state, state);
return rc;
}
@@ -1361,24 +1444,23 @@
inst = q->drv_priv;
if (!inst || !vb) {
- pr_err("Invalid input: %p, %p\n", inst, vb);
+ dprintk(VIDC_ERR, "Invalid input: %p, %p\n", inst, vb);
return -EINVAL;
}
if (inst->state != MSM_VIDC_START_DONE) {
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
- pr_err("Out of memory\n");
+ dprintk(VIDC_ERR, "Out of memory\n");
goto err_no_mem;
}
entry->vb = vb;
- pr_debug("Queueing buffer in pendingq\n");
+ dprintk(VIDC_DBG, "Queueing buffer in pendingq\n");
spin_lock_irqsave(&inst->lock, flags);
list_add_tail(&entry->list, &inst->pendingq);
spin_unlock_irqrestore(&inst->lock, flags);
} else {
int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
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;
frame_data.filled_len = vb->v4l2_planes[0].bytesused;
@@ -1390,21 +1472,24 @@
frame_data.buffer_type = HAL_BUFFER_INPUT;
if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
frame_data.flags |= HAL_BUFFERFLAG_EOS;
- pr_debug("Received EOS on output capability\n");
+ dprintk(VIDC_DBG,
+ "Received EOS on output capability\n");
}
if (vb->v4l2_buf.flags &
V4L2_QCOM_BUF_FLAG_CODECCONFIG) {
frame_data.flags |= HAL_BUFFERFLAG_CODECCONFIG;
- pr_debug("Received CODECCONFIG on output capability\n");
+ dprintk(VIDC_DBG,
+ "Received CODECCONFIG on output cap\n");
}
-
- pr_debug("Sending etb to hal: Alloc: %d :filled: %d\n",
+ dprintk(VIDC_DBG,
+ "Sending etb to hal: Alloc: %d :filled: %d\n",
frame_data.alloc_len, frame_data.filled_len);
rc = vidc_hal_session_etb((void *) inst->session,
&frame_data);
- pr_debug("Sent etb to HAL\n");
+ dprintk(VIDC_DBG, "Sent etb to HAL\n");
} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct vidc_seq_hdr seq_hdr;
frame_data.filled_len = 0;
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
if (inst->extradata_handle) {
@@ -1413,20 +1498,38 @@
} else {
frame_data.extradata_addr = 0;
}
- pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d",
+ dprintk(VIDC_DBG,
+ "Sending ftb to hal: Alloc: %d :filled: %d",
frame_data.alloc_len, frame_data.filled_len);
- pr_debug(" extradata_addr: %d\n",
+ dprintk(VIDC_DBG,
+ " extradata_addr: %d\n",
frame_data.extradata_addr);
- rc = vidc_hal_session_ftb((void *) inst->session,
- &frame_data);
+ if (!inst->ftb_count &&
+ inst->session_type == MSM_VIDC_ENCODER) {
+ seq_hdr.seq_hdr = (u8 *) vb->v4l2_planes[0].
+ m.userptr;
+ seq_hdr.seq_hdr_len = vb->v4l2_planes[0].length;
+ rc = vidc_hal_session_get_seq_hdr((void *)
+ inst->session, &seq_hdr);
+ if (!rc) {
+ inst->vb2_seq_hdr = vb;
+ dprintk(VIDC_DBG, "Seq_hdr: %p\n",
+ inst->vb2_seq_hdr);
+ }
+ } else {
+ rc = vidc_hal_session_ftb((void *)
+ inst->session, &frame_data);
+ }
+ inst->ftb_count++;
} else {
- pr_err("This capability is not supported: %d\n",
+ dprintk(VIDC_ERR,
+ "This capability is not supported: %d\n",
q->type);
rc = -EINVAL;
}
}
if (rc)
- pr_err("Failed to queue buffer\n");
+ dprintk(VIDC_ERR, "Failed to queue buffer\n");
err_no_mem:
return rc;
}
@@ -1439,14 +1542,15 @@
&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
rc = vidc_hal_session_get_buf_req((void *) inst->session);
if (rc) {
- pr_err("Failed to get property\n");
+ dprintk(VIDC_ERR, "Failed to get property\n");
goto exit;
}
rc = wait_for_completion_timeout(
&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
- pr_err("Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR,
+ "Wait interrupted or timeout: %d\n", rc);
rc = -EIO;
goto exit;
}
@@ -1467,10 +1571,10 @@
struct hal_buffer_requirements *scratch_buf =
&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_SCRATCH];
int i;
-
- pr_debug("scratch: num = %d, size = %d\n",
- scratch_buf->buffer_count_actual,
- scratch_buf->buffer_size);
+ dprintk(VIDC_DBG,
+ "scratch: num = %d, size = %d\n",
+ scratch_buf->buffer_count_actual,
+ scratch_buf->buffer_size);
spin_lock_irqsave(&inst->lock, flags);
if (!list_empty(&inst->internalbufs)) {
list_for_each_safe(ptr, next, &inst->internalbufs) {
@@ -1490,13 +1594,14 @@
inst->core->resources.io_map[NS_MAP].domain,
0, 0);
if (!handle) {
- pr_err("Failed to allocate scratch memory\n");
+ dprintk(VIDC_ERR,
+ "Failed to allocate scratch memory\n");
rc = -ENOMEM;
goto err_no_mem;
}
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
- pr_err("Out of memory\n");
+ dprintk(VIDC_ERR, "Out of memory\n");
rc = -ENOMEM;
goto fail_kzalloc;
}
@@ -1508,7 +1613,8 @@
rc = vidc_hal_session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
- pr_err("vidc_hal_session_set_buffers failed");
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed");
goto fail_set_buffers;
}
spin_lock_irqsave(&inst->lock, flags);
@@ -1535,11 +1641,13 @@
struct hal_buffer_requirements *persist_buf =
&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
int i;
- pr_debug("persist: num = %d, size = %d\n",
+ dprintk(VIDC_DBG,
+ "persist: num = %d, size = %d\n",
persist_buf->buffer_count_actual,
persist_buf->buffer_size);
if (!list_empty(&inst->persistbufs)) {
- pr_err("Persist buffers already allocated\n");
+ dprintk(VIDC_ERR,
+ "Persist buffers already allocated\n");
return rc;
}
@@ -1550,13 +1658,14 @@
inst->core->resources.io_map[NS_MAP].domain,
0, 0);
if (!handle) {
- pr_err("Failed to allocate persist memory\n");
+ dprintk(VIDC_ERR,
+ "Failed to allocate persist memory\n");
rc = -ENOMEM;
goto err_no_mem;
}
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
- pr_err("Out of memory\n");
+ dprintk(VIDC_ERR, "Out of memory\n");
rc = -ENOMEM;
goto fail_kzalloc;
}
@@ -1568,7 +1677,8 @@
rc = vidc_hal_session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
- pr_err("vidc_hal_session_set_buffers failed");
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed");
goto fail_set_buffers;
}
spin_lock_irqsave(&inst->lock, flags);
@@ -1594,7 +1704,7 @@
op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
if (ip_flush && !op_flush) {
- pr_warn("Input only flush not supported\n");
+ dprintk(VIDC_WARN, "Input only flush not supported\n");
return 0;
}
mutex_lock(&inst->sync_lock);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
new file mode 100644
index 0000000..7921f84
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_vidc_debug.h"
+
+#define MAX_DBG_BUF_SIZE 4096
+int msm_vidc_debug;
+
+struct debug_buffer {
+ char ptr[MAX_DBG_BUF_SIZE];
+ char *curr;
+ u32 filled_size;
+};
+
+static struct debug_buffer dbg_buf;
+
+#define INIT_DBG_BUF(__buf) ({ \
+ __buf.curr = __buf.ptr;\
+ __buf.filled_size = 0; \
+})
+
+static int core_info_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...)
+{
+ va_list args;
+ u32 size;
+ va_start(args, fmt);
+ size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args);
+ va_end(args);
+ buffer->curr += size;
+ buffer->filled_size += size;
+ return size;
+}
+
+static ssize_t core_info_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_vidc_core *core = file->private_data;
+ int i = 0;
+ if (!core) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
+ return 0;
+ }
+ INIT_DBG_BUF(dbg_buf);
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "CORE %d: 0x%p\n", core->id, core);
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "state: %d\n", core->state);
+ write_str(&dbg_buf, "base addr: 0x%x\n", core->base_addr);
+ write_str(&dbg_buf, "register_base: 0x%x\n", core->register_base);
+ write_str(&dbg_buf, "register_size: %u\n", core->register_size);
+ write_str(&dbg_buf, "irq: %u\n", core->irq);
+ for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
+ write_str(&dbg_buf, "completions[%d]: %s\n", i,
+ completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
+ "pending" : "done");
+ }
+ return simple_read_from_buffer(buf, count, ppos,
+ dbg_buf.ptr, dbg_buf.filled_size);
+}
+
+static const struct file_operations core_info_fops = {
+ .open = core_info_open,
+ .read = core_info_read,
+};
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+ struct dentry *parent)
+{
+ struct dentry *dir = NULL;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+ if (!core) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
+ goto failed_create_dir;
+ }
+ msm_vidc_debug = 0;
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+ dir = debugfs_create_dir(debugfs_name, parent);
+ if (!dir) {
+ dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_u32("debug_level", S_IRUGO | S_IWUSR,
+ parent, &msm_vidc_debug)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+failed_create_dir:
+ return dir;
+}
+
+static int inst_info_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t inst_info_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_vidc_inst *inst = file->private_data;
+ int i, j;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid params, core: %p\n", inst);
+ return 0;
+ }
+ INIT_DBG_BUF(dbg_buf);
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "INSTANCE: 0x%p (%s)\n", inst,
+ inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
+ write_str(&dbg_buf, "===============================\n");
+ write_str(&dbg_buf, "core: 0x%p\n", inst->core);
+ write_str(&dbg_buf, "height: %d\n", inst->prop.height);
+ write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+ write_str(&dbg_buf, "state: %d\n", inst->state);
+ write_str(&dbg_buf, "-----------Formats-------------\n");
+ for (i = 0; i < MAX_PORT_NUM; i++) {
+ write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ?
+ "Output" : "Capture");
+ write_str(&dbg_buf, "name : %s\n", inst->fmts[i]->name);
+ write_str(&dbg_buf, "planes : %d\n", inst->fmts[i]->num_planes);
+ write_str(
+ &dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
+ "Output" : "Capture");
+ for (j = 0; j < inst->fmts[i]->num_planes; j++)
+ write_str(&dbg_buf, "size for plane %d: %u\n", j,
+ inst->fmts[i]->get_frame_size(j,
+ inst->prop.height, inst->prop.width));
+ }
+ write_str(&dbg_buf, "-------------------------------\n");
+ for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
+ write_str(&dbg_buf, "completions[%d]: %s\n", i,
+ completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
+ "pending" : "done");
+ }
+ return simple_read_from_buffer(buf, count, ppos,
+ dbg_buf.ptr, dbg_buf.filled_size);
+}
+
+static const struct file_operations inst_info_fops = {
+ .open = inst_info_open,
+ .read = inst_info_read,
+};
+
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+ struct dentry *parent)
+{
+ struct dentry *dir = NULL;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid params, inst: %p\n", inst);
+ goto failed_create_dir;
+ }
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
+ dir = debugfs_create_dir(debugfs_name, parent);
+ if (!dir) {
+ dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+ goto failed_create_dir;
+ }
+ if (!debugfs_create_file("info", S_IRUGO, dir, inst, &inst_info_fops)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
+
+failed_create_dir:
+ return dir;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
new file mode 100644
index 0000000..b7928e9
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_VIDC_DEBUG__
+#define __MSM_VIDC_DEBUG__
+#include <linux/debugfs.h>
+#include "msm_vidc_internal.h"
+
+#define VIDC_DBG_TAG "msm_vidc: %d: "
+
+enum vidc_msg_prio {
+ VIDC_ERR,
+ VIDC_WARN,
+ VIDC_INFO,
+ VIDC_DBG,
+};
+
+extern int msm_vidc_debug;
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (msm_vidc_debug >= level) \
+ printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
+ level, ## arg); \
+ } while (0)
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+ struct dentry *parent);
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+ struct dentry *parent);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 29ed6dc..55aec74 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -243,6 +243,10 @@
bool in_reconfig;
u32 reconfig_width;
u32 reconfig_height;
+ struct dentry *debugfs_root;
+ u32 ftb_count;
+ u32 fbd_count;
+ struct vb2_buffer *vb2_seq_hdr;
};
extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 8e9e57f..2b01882 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -21,6 +21,7 @@
#include <asm/memory.h>
#include "vidc_hal.h"
#include "vidc_hal_io.h"
+#include "msm_vidc_debug.h"
#define FIRMWARE_SIZE 0X00A00000
#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
@@ -37,7 +38,7 @@
u8 i;
if (!packet) {
- HAL_MSG_ERROR("Invalid Param: %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Param");
return;
}
@@ -129,26 +130,25 @@
u32 *write_ptr;
if (!info || !packet || !rx_req_is_set) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
qinfo = (struct vidc_iface_q_info *) info;
- HAL_MSG_LOW("In %s: ", __func__);
hal_virtio_modify_cmd_packet(packet);
queue = (struct hfi_queue_header *) qinfo->q_hdr;
if (!queue) {
- HAL_MSG_ERROR("queue not present");
+ dprintk(VIDC_ERR, "queue not present");
return -ENOENT;
}
packet_size_in_words = (*(u32 *)packet) >> 2;
- HAL_MSG_LOW("Packet_size in words: %d", packet_size_in_words);
+ dprintk(VIDC_DBG, "Packet_size in words: %d", packet_size_in_words);
if (packet_size_in_words == 0) {
- HAL_MSG_ERROR("Zero packet size");
+ dprintk(VIDC_ERR, "Zero packet size");
return -ENODATA;
}
@@ -157,10 +157,10 @@
empty_space = (queue->qhdr_write_idx >= read_idx) ?
(queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
(read_idx - queue->qhdr_write_idx);
- HAL_MSG_LOW("Empty_space: %d", empty_space);
+ dprintk(VIDC_DBG, "Empty_space: %d", empty_space);
if (empty_space <= packet_size_in_words) {
queue->qhdr_tx_req = 1;
- HAL_MSG_ERROR("Insufficient size (%d) to write (%d)",
+ dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)",
empty_space, packet_size_in_words);
return -ENOTEMPTY;
}
@@ -170,7 +170,7 @@
new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
(queue->qhdr_write_idx << 2));
- HAL_MSG_LOW("Write Ptr: %d", (u32) write_ptr);
+ dprintk(VIDC_DBG, "Write Ptr: %d", (u32) write_ptr);
if (new_write_idx < queue->qhdr_q_size) {
memcpy(write_ptr, packet, packet_size_in_words << 2);
} else {
@@ -183,7 +183,7 @@
}
queue->qhdr_write_idx = new_write_idx;
*rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
- HAL_MSG_LOW("Out %s: ", __func__);
+ dprintk(VIDC_DBG, "Out : ");
return 0;
}
@@ -193,7 +193,7 @@
struct hal_session *sess;
if (!packet) {
- HAL_MSG_ERROR("Invalid Param: %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Param: ");
return;
}
@@ -248,16 +248,15 @@
struct vidc_iface_q_info *qinfo;
if (!info || !packet || !pb_tx_req_is_set) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
}
qinfo = (struct vidc_iface_q_info *) info;
- HAL_MSG_LOW("In %s: ", __func__);
queue = (struct hfi_queue_header *) qinfo->q_hdr;
if (!queue) {
- HAL_MSG_ERROR("Queue memory is not allocated\n");
+ dprintk(VIDC_ERR, "Queue memory is not allocated\n");
return -ENOMEM;
}
@@ -270,14 +269,14 @@
read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
(queue->qhdr_read_idx << 2));
packet_size_in_words = (*read_ptr) >> 2;
- HAL_MSG_LOW("packet_size_in_words: %d", packet_size_in_words);
+ dprintk(VIDC_DBG, "packet_size_in_words: %d", packet_size_in_words);
if (packet_size_in_words == 0) {
- HAL_MSG_ERROR("Zero packet size");
+ dprintk(VIDC_ERR, "Zero packet size");
return -ENODATA;
}
new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
- HAL_MSG_LOW("Read Ptr: %d", (u32) new_read_idx);
+ dprintk(VIDC_DBG, "Read Ptr: %d", (u32) new_read_idx);
if (new_read_idx < queue->qhdr_q_size) {
memcpy(packet, read_ptr,
packet_size_in_words << 2);
@@ -299,7 +298,7 @@
*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
hal_virtio_modify_msg_packet(packet);
- HAL_MSG_LOW("Out %s: ", __func__);
+ dprintk(VIDC_DBG, "Out : ");
return 0;
}
@@ -311,25 +310,25 @@
int rc = 0;
if (!mem || !clnt || !size) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
}
vmem = (struct vidc_mem_addr *)mem;
- HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
+ dprintk(VIDC_WARN, "start to alloc: size:%d, Flags: %d", size, flags);
alloc = msm_smem_alloc(clnt, size, align, flags, domain, 1, 1);
- HAL_MSG_LOW("Alloc done");
+ dprintk(VIDC_DBG, "Alloc done");
if (!alloc) {
- HAL_MSG_HIGH("Alloc fail in %s", __func__);
+ dprintk(VIDC_ERR, "Alloc failed\n");
rc = -ENOMEM;
goto fail_smem_alloc;
}
rc = msm_smem_clean_invalidate(clnt, alloc);
if (rc) {
- pr_err("NOTE: Failed to clean caches\n");
+ dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
goto fail_clean_cache;
}
- HAL_MSG_MEDIUM("vidc_hal_alloc:ptr=%p,size=%d",
+ dprintk(VIDC_DBG, "vidc_hal_alloc:ptr=%p,size=%d",
alloc->kvaddr, size);
vmem->mem_size = alloc->size;
vmem->mem_data = alloc;
@@ -370,7 +369,7 @@
}
hwiosymaddr = ((u32)base_addr + (hwiosymaddr));
- HAL_MSG_LOW("Base addr: 0x%x, written to: 0x%x, Value: 0x%x...",
+ dprintk(VIDC_DBG, "Base addr: 0x%x, written to: 0x%x, Value: 0x%x...",
(u32)base_addr, hwiosymaddr, value);
writel_relaxed(value, hwiosymaddr);
wmb();
@@ -390,14 +389,14 @@
int result = -EPERM;
if (!device || !pkt) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
}
spin_lock(&device->write_lock);
q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
if (!q_info) {
- HAL_MSG_ERROR("cannot write to shared Q's");
+ dprintk(VIDC_ERR, "cannot write to shared Q's");
goto err_q_write;
}
@@ -408,7 +407,7 @@
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
result = 0;
} else {
- HAL_MSG_ERROR("vidc_hal_iface_cmdq_write:queue_full");
+ dprintk(VIDC_ERR, "vidc_hal_iface_cmdq_write:queue_full");
}
err_q_write:
spin_unlock(&device->write_lock);
@@ -422,13 +421,13 @@
struct vidc_iface_q_info *q_info;
if (!pkt) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
}
spin_lock(&device->read_lock);
if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
q_array.align_virtual_addr == 0) {
- HAL_MSG_ERROR("cannot read from shared MSG Q's");
+ dprintk(VIDC_ERR, "cannot read from shared MSG Q's");
rc = -ENODATA;
goto read_error;
}
@@ -441,7 +440,7 @@
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
} else {
- HAL_MSG_ERROR("vidc_hal_iface_msgq_read:queue_empty");
+ dprintk(VIDC_INFO, "vidc_hal_iface_msgq_read:queue_empty");
rc = -ENODATA;
}
read_error:
@@ -456,13 +455,13 @@
struct vidc_iface_q_info *q_info;
if (!pkt) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
}
spin_lock(&device->read_lock);
if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
q_array.align_virtual_addr == 0) {
- HAL_MSG_ERROR("cannot read from shared DBG Q's");
+ dprintk(VIDC_ERR, "cannot read from shared DBG Q's");
rc = -ENODATA;
goto dbg_error;
}
@@ -474,7 +473,7 @@
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
} else {
- HAL_MSG_MEDIUM("vidc_hal_iface_dbgq_read:queue_empty");
+ dprintk(VIDC_INFO, "vidc_hal_iface_dbgq_read:queue_empty");
rc = -ENODATA;
}
dbg_error:
@@ -529,7 +528,7 @@
dev->hal_client,
VIDC_IFACEQ_TABLE_SIZE, 1, SMEM_UNCACHED, domain);
if (rc) {
- HAL_MSG_ERROR("%s:iface_q_table_alloc_fail", __func__);
+ dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
return -ENOMEM;
}
q_tbl_hdr = (struct hfi_queue_table_header *)
@@ -549,8 +548,7 @@
dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
1, SMEM_UNCACHED, domain);
if (rc) {
- HAL_MSG_ERROR("%s:iface_q_table_alloc[%d]_fail",
- __func__, i);
+ dprintk(VIDC_ERR, "iface_q_table_alloc[%d]_fail", i);
vidc_hal_interface_queues_release(dev);
return -ENOMEM;
} else {
@@ -638,7 +636,7 @@
if (device) {
dev = device;
} else {
- HAL_MSG_ERROR("%s:invalid device", __func__);
+ dprintk(VIDC_ERR, "Invalid device");
return -ENODEV;
}
enable_irq(dev->hal_data->irq);
@@ -653,30 +651,30 @@
if (!dev->hal_client) {
dev->hal_client = msm_smem_new_client(SMEM_ION);
if (dev->hal_client == NULL) {
- HAL_MSG_ERROR("Failed to alloc ION_Client");
+ dprintk(VIDC_ERR, "Failed to alloc ION_Client");
rc = -ENODEV;
goto err_no_mem;
}
- HAL_MSG_ERROR("Device_Virt_Address : 0x%x,"
+ dprintk(VIDC_DBG, "Device_Virt_Address : 0x%x,"
"Register_Virt_Addr: 0x%x",
dev->hal_data->device_base_addr,
(u32) dev->hal_data->register_base_addr);
rc = vidc_hal_interface_queues_init(dev, domain);
if (rc) {
- HAL_MSG_ERROR("failed to init queues");
+ dprintk(VIDC_ERR, "failed to init queues");
rc = -ENOMEM;
goto err_no_mem;
}
} else {
- HAL_MSG_ERROR("hal_client exists");
+ dprintk(VIDC_ERR, "hal_client exists");
rc = -EEXIST;
goto err_no_mem;
}
rc = vidc_hal_core_start_cpu(dev);
if (rc) {
- HAL_MSG_ERROR("Failed to start core");
+ dprintk(VIDC_ERR, "Failed to start core");
rc = -ENODEV;
goto err_no_dev;
}
@@ -701,14 +699,14 @@
if (device) {
dev = device;
} else {
- HAL_MSG_ERROR("%s:invalid device", __func__);
+ dprintk(VIDC_ERR, "invalid device");
return -ENODEV;
}
write_register(dev->hal_data->register_base_addr,
VIDC_CPU_CS_SCIACMDARG3, 0, 0);
disable_irq_nosync(dev->hal_data->irq);
vidc_hal_interface_queues_release(dev);
- HAL_MSG_INFO("\nHAL exited\n");
+ dprintk(VIDC_INFO, "HAL exited\n");
return 0;
}
@@ -721,7 +719,7 @@
if (device) {
dev = device;
} else {
- HAL_MSG_ERROR("%s:invalid device", __func__);
+ dprintk(VIDC_ERR, "invalid device");
return -ENODEV;
}
pkt.size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
@@ -745,11 +743,11 @@
if ((intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK) ||
(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) {
device->intr_status |= intr_status;
- HAL_MSG_ERROR("INTERRUPT for device: 0x%x: "
+ dprintk(VIDC_DBG, "INTERRUPT for device: 0x%x: "
"times: %d interrupt_status: %d",
(u32) device, ++device->reg_count, intr_status);
} else {
- HAL_MSG_ERROR("SPURIOUS_INTR for device: 0x%x: "
+ dprintk(VIDC_WARN, "SPURIOUS_INTR for device: 0x%x: "
"times: %d interrupt_status: %d",
(u32) device, ++device->spur_count, intr_status);
}
@@ -757,7 +755,7 @@
VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
write_register(device->hal_data->register_base_addr,
VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
- HAL_MSG_ERROR("Cleared WRAPPER/A2H interrupt");
+ dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
}
int vidc_hal_core_set_resource(void *device,
@@ -769,7 +767,7 @@
struct hal_device *dev;
if (!device || !resource_hdr || !resource_value) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "set_res: Invalid Params");
return -EINVAL;
} else {
dev = device;
@@ -799,8 +797,8 @@
break;
}
default:
- HAL_MSG_INFO("In %s called for resource %d",
- __func__, resource_hdr->resource_id);
+ dprintk(VIDC_INFO, "Invalid res_id in set_res %d",
+ resource_hdr->resource_id);
break;
}
return rc;
@@ -814,7 +812,7 @@
struct hal_device *dev;
if (!device || !resource_hdr) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Inv-Params in rel_res");
return -EINVAL;
} else {
dev = device;
@@ -839,7 +837,7 @@
if (device) {
dev = device;
} else {
- HAL_MSG_ERROR("%s:invalid device", __func__);
+ dprintk(VIDC_ERR, "invalid device");
return -ENODEV;
}
pkt.size = sizeof(struct hfi_cmd_sys_ping_packet);
@@ -878,7 +876,8 @@
buffer = HFI_BUFFER_INTERNAL_PERSIST;
break;
default:
- HAL_MSG_ERROR("Invalid buffer type : 0x%x\n", hal_buffer);
+ dprintk(VIDC_ERR, "Invalid buffer :0x%x\n",
+ hal_buffer);
buffer = 0;
break;
}
@@ -893,13 +892,13 @@
struct hal_session *session;
if (!sess || !pdata) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
}
- HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
+ dprintk(VIDC_INFO, "in set_prop,with prop id: 0x%x", ptype);
pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
pkt->session_id = (u32) session;
@@ -1001,7 +1000,7 @@
(struct hal_nal_stream_format_supported *)pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
- HAL_MSG_ERROR("\ndata is :%d",
+ dprintk(VIDC_DBG, "data is :%d",
prop->nal_stream_format_supported);
switch (prop->nal_stream_format_supported) {
case HAL_NAL_FORMAT_STARTCODES:
@@ -1025,7 +1024,7 @@
HFI_NAL_FORMAT_FOUR_BYTE_LENGTH;
break;
default:
- HAL_MSG_ERROR("Invalid nal format: 0x%x",
+ dprintk(VIDC_ERR, "Invalid nal format: 0x%x",
prop->nal_stream_format_supported);
break;
}
@@ -1045,7 +1044,7 @@
pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY;
break;
default:
- HAL_MSG_ERROR("invalid output order: 0x%x",
+ dprintk(VIDC_ERR, "invalid output order: 0x%x",
*data);
break;
}
@@ -1132,7 +1131,7 @@
pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6;
break;
default:
- HAL_MSG_ERROR("Invalid divx format: 0x%x", *data);
+ dprintk(VIDC_ERR, "Invalid divx format: 0x%x", *data);
break;
}
pkt->size += sizeof(u32) * 2;
@@ -1221,13 +1220,15 @@
hfi->cabac_model = HFI_H264_CABAC_MODEL_2;
break;
default:
- HAL_MSG_ERROR("Invalid cabac model 0x%x",
- prop->entropy_mode);
+ dprintk(VIDC_ERR,
+ "Invalid cabac model 0x%x",
+ prop->entropy_mode);
break;
}
break;
default:
- HAL_MSG_ERROR("Invalid entropy selected: 0x%x",
+ dprintk(VIDC_ERR,
+ "Invalid entropy selected: 0x%x",
prop->cabac_model);
break;
}
@@ -1237,11 +1238,11 @@
}
case HAL_PARAM_VENC_RATE_CONTROL:
{
- u32 *rc_mode;
+ u32 *rc;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
- rc_mode = (u32 *)pdata;
- switch ((enum hal_rate_control) *rc_mode) {
+ rc = (u32 *)pdata;
+ switch ((enum hal_rate_control) *rc) {
case HAL_RATE_CONTROL_OFF:
pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
break;
@@ -1258,7 +1259,7 @@
pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
break;
default:
- HAL_MSG_ERROR("Invalid Rate control setting: 0x%x",
+ dprintk(VIDC_ERR, "Invalid Rate control setting: 0x%x",
(int) pdata);
break;
}
@@ -1308,7 +1309,7 @@
hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY;
break;
default:
- HAL_MSG_ERROR("Invalid deblocking mode: 0x%x",
+ dprintk(VIDC_ERR, "Invalid deblocking mode: 0x%x",
prop->mode);
break;
}
@@ -1376,7 +1377,7 @@
hfi->mode = HFI_INTRA_REFRESH_RANDOM;
break;
default:
- HAL_MSG_ERROR("Invalid intra refresh setting: 0x%x",
+ dprintk(VIDC_ERR, "Invalid intra refresh setting: 0x%x",
prop->mode);
break;
}
@@ -1409,7 +1410,7 @@
hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT;
break;
default:
- HAL_MSG_ERROR("Invalid slice settings: 0x%x",
+ dprintk(VIDC_ERR, "Invalid slice settings: 0x%x",
prop->multi_slice);
break;
}
@@ -1459,7 +1460,7 @@
case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
case HAL_PARAM_VENC_LOW_LATENCY:
default:
- HAL_MSG_INFO("DEFAULT: Calling 0x%x", ptype);
+ dprintk(VIDC_INFO, "DEFAULT: Calling 0x%x", ptype);
break;
}
if (vidc_hal_iface_cmdq_write(session->device, pkt))
@@ -1473,12 +1474,12 @@
struct hal_session *session;
if (!sess || !pdata) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
}
- HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
+ dprintk(VIDC_INFO, "IN func: , with property id: %d", ptype);
switch (ptype) {
case HAL_CONFIG_FRAME_RATE:
@@ -1584,7 +1585,7 @@
case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
case HAL_PARAM_VENC_LOW_LATENCY:
default:
- HAL_MSG_INFO("DEFAULT: Calling 0x%x", ptype);
+ dprintk(VIDC_INFO, "DEFAULT: Calling 0x%x", ptype);
break;
}
return 0;
@@ -1600,7 +1601,7 @@
if (device) {
dev = device;
} else {
- HAL_MSG_ERROR("%s:invalid device", __func__);
+ dprintk(VIDC_ERR, ":invalid device");
return NULL;
}
@@ -1633,7 +1634,7 @@
if (session_id) {
session = session_id;
} else {
- HAL_MSG_ERROR("%s:invalid session", __func__);
+ dprintk(VIDC_ERR, ":invalid session");
return -ENODEV;
}
@@ -1669,7 +1670,7 @@
struct hal_session *session;
if (!sess || !buffer_info) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
@@ -1716,7 +1717,7 @@
pkt->buffer_type = buffer;
else
return -EINVAL;
- HAL_MSG_INFO("set buffers: 0x%x", buffer_info->buffer_type);
+ dprintk(VIDC_INFO, "set buffers: 0x%x", buffer_info->buffer_type);
if (vidc_hal_iface_cmdq_write(session->device, pkt))
rc = -ENOTEMPTY;
return rc;
@@ -1733,7 +1734,7 @@
struct hal_session *session;
if (!sess || !buffer_info) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
@@ -1777,7 +1778,7 @@
pkt->buffer_type = buffer;
else
return -EINVAL;
- HAL_MSG_INFO("Release buffers: 0x%x", buffer_info->buffer_type);
+ dprintk(VIDC_INFO, "Release buffers: 0x%x", buffer_info->buffer_type);
if (vidc_hal_iface_cmdq_write(session->device, pkt))
rc = -ENOTEMPTY;
return rc;
@@ -1825,7 +1826,7 @@
struct hal_session *session;
if (!sess || !input_frame) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
@@ -1847,7 +1848,7 @@
pkt.filled_len = input_frame->filled_len;
pkt.input_tag = input_frame->clnt_data;
pkt.packet_buffer = (u8 *) input_frame->device_addr;
- HAL_MSG_ERROR("### Q DECODER INPUT BUFFER ###");
+ dprintk(VIDC_DBG, "Q DECODER INPUT BUFFER");
if (vidc_hal_iface_cmdq_write(session->device, &pkt))
rc = -ENOTEMPTY;
} else {
@@ -1868,7 +1869,7 @@
pkt.filled_len = input_frame->filled_len;
pkt.input_tag = input_frame->clnt_data;
pkt.packet_buffer = (u8 *) input_frame->device_addr;
- HAL_MSG_ERROR("### Q ENCODER INPUT BUFFER ###");
+ dprintk(VIDC_DBG, "Q ENCODER INPUT BUFFER");
if (vidc_hal_iface_cmdq_write(session->device, &pkt))
rc = -ENOTEMPTY;
}
@@ -1883,7 +1884,7 @@
struct hal_session *session;
if (!sess || !output_frame) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
@@ -1900,7 +1901,7 @@
pkt.extra_data_buffer =
(u8 *) output_frame->extradata_addr;
- HAL_MSG_INFO("### Q OUTPUT BUFFER ###");
+ dprintk(VIDC_INFO, "### Q OUTPUT BUFFER ###");
if (vidc_hal_iface_cmdq_write(session->device, &pkt))
rc = -ENOTEMPTY;
return rc;
@@ -1915,7 +1916,7 @@
struct hal_session *session;
if (!sess || !seq_hdr) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
@@ -1942,7 +1943,7 @@
struct hal_session *session;
if (!sess || !seq_hdr) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return -EINVAL;
} else {
session = sess;
@@ -1969,7 +1970,7 @@
if (sess) {
session = sess;
} else {
- HAL_MSG_ERROR("%s:invalid session", __func__);
+ dprintk(VIDC_ERR, ":invalid session");
return -ENODEV;
}
@@ -1992,7 +1993,7 @@
if (sess) {
session = sess;
} else {
- HAL_MSG_ERROR("%s:invalid session", __func__);
+ dprintk(VIDC_ERR, ":invalid session");
return -ENODEV;
}
@@ -2013,7 +2014,7 @@
pkt.flush_type = HFI_FLUSH_ALL;
break;
default:
- HAL_MSG_ERROR("Invalid flush mode: 0x%x\n", flush_mode);
+ dprintk(VIDC_ERR, "Invalid flush mode: 0x%x\n", flush_mode);
break;
}
if (vidc_hal_iface_cmdq_write(session->device, &pkt))
@@ -2060,12 +2061,12 @@
FIRMWARE_SIZE))) {
return 0;
} else {
- HAL_MSG_INFO("Device not registered");
+ dprintk(VIDC_INFO, "Device not registered");
return -EINVAL;
}
}
} else {
- HAL_MSG_INFO("no device Registered");
+ dprintk(VIDC_INFO, "no device Registered");
}
return -EINVAL;
}
@@ -2075,9 +2076,9 @@
struct hal_device *device = list_first_entry(
&hal_ctxt.dev_head, struct hal_device, list);
- HAL_MSG_INFO(" GOT INTERRUPT %s() ", __func__);
+ dprintk(VIDC_INFO, " GOT INTERRUPT () ");
if (!device->callback) {
- HAL_MSG_ERROR("No callback function "
+ dprintk(VIDC_ERR, "No callback function "
"to process interrupt: %p\n", device);
return;
}
@@ -2090,10 +2091,10 @@
static irqreturn_t vidc_hal_isr(int irq, void *dev)
{
struct hal_device *device = dev;
- HAL_MSG_MEDIUM("\n vidc_hal_isr() %d ", irq);
+ dprintk(VIDC_INFO, "vidc_hal_isr() %d ", irq);
disable_irq_nosync(irq);
queue_work(device->vidc_workq, &vidc_hal_work);
- HAL_MSG_MEDIUM("\n vidc_hal_isr() %d ", irq);
+ dprintk(VIDC_INFO, "vidc_hal_isr() %d ", irq);
return IRQ_HANDLED;
}
@@ -2107,19 +2108,19 @@
if (device_id || !reg_base || !reg_size ||
!irq || !callback) {
- HAL_MSG_ERROR("Invalid Paramters");
+ dprintk(VIDC_ERR, "Invalid Paramters");
return NULL;
} else {
- HAL_MSG_INFO("entered %s, device_id: %d", __func__, device_id);
+ dprintk(VIDC_INFO, "entered , device_id: %d", device_id);
}
if (vidc_hal_check_core_registered(hal_ctxt, fw_base_addr,
reg_base, reg_size, irq)) {
- HAL_MSG_LOW("HAL_DATA will be assigned now");
+ dprintk(VIDC_DBG, "HAL_DATA will be assigned now");
hal = (struct hal_data *)
kzalloc(sizeof(struct hal_data), GFP_KERNEL);
if (!hal) {
- HAL_MSG_ERROR("Failed to alloc");
+ dprintk(VIDC_ERR, "Failed to alloc");
return NULL;
}
hal->irq = irq;
@@ -2127,20 +2128,21 @@
hal->register_base_addr =
ioremap_nocache(reg_base, reg_size);
if (!hal->register_base_addr) {
- HAL_MSG_ERROR("could not map reg addr %d of size %d",
- reg_base, reg_size);
+ dprintk(VIDC_ERR,
+ "could not map reg addr %d of size %d",
+ reg_base, reg_size);
goto err_map;
}
INIT_LIST_HEAD(&hal_ctxt.dev_head);
} else {
- HAL_MSG_ERROR("Core present/Already added");
+ dprintk(VIDC_ERR, "Core present/Already added");
return NULL;
}
hdevice = (struct hal_device *)
kzalloc(sizeof(struct hal_device), GFP_KERNEL);
if (!hdevice) {
- HAL_MSG_ERROR("failed to allocate new device");
+ dprintk(VIDC_ERR, "failed to allocate new device");
goto err_map;
}
@@ -2154,14 +2156,14 @@
hdevice->vidc_workq = create_singlethread_workqueue(
"msm_vidc_workerq");
if (!hdevice->vidc_workq) {
- HAL_MSG_ERROR("%s: create workq failed\n", __func__);
+ dprintk(VIDC_ERR, ": create workq failed\n");
goto error_createq;
}
rc = request_irq(irq, vidc_hal_isr, IRQF_TRIGGER_HIGH,
"msm_vidc", hdevice);
if (unlikely(rc)) {
- HAL_MSG_ERROR("%s() :request_irq failed\n", __func__);
+ dprintk(VIDC_ERR, "() :request_irq failed\n");
goto error_irq_fail;
}
disable_irq_nosync(irq);
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 364faa9..795024d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include "vidc_hal.h"
+#include "msm_vidc_debug.h"
static enum vidc_status vidc_map_hal_err_status(int hfi_err)
{
@@ -81,10 +82,10 @@
struct hfi_frame_size frame_sz;
u8 *data_ptr;
int prop_id;
- HAL_MSG_LOW("RECEIVED:EVENT_NOTIFY");
+ dprintk(VIDC_DBG, "RECEIVED:EVENT_NOTIFY");
if (sizeof(struct hfi_msg_event_notify_packet)
> pkt->size) {
- HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+ dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
return;
}
@@ -139,30 +140,30 @@
static void hal_process_event_notify(struct hal_device *device,
struct hfi_msg_event_notify_packet *pkt)
{
- HAL_MSG_LOW("RECVD:EVENT_NOTIFY");
+ dprintk(VIDC_DBG, "RECVD:EVENT_NOTIFY");
if (!device || !pkt ||
pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params");
return;
}
switch (pkt->event_id) {
case HFI_EVENT_SYS_ERROR:
- HAL_MSG_INFO("HFI_EVENT_SYS_ERROR");
+ dprintk(VIDC_INFO, "HFI_EVENT_SYS_ERROR");
break;
case HFI_EVENT_SESSION_ERROR:
- HAL_MSG_INFO("HFI_EVENT_SESSION_ERROR");
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
break;
case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
- HAL_MSG_INFO("HFI_EVENT_SESSION_SEQUENCE_CHANGED");
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
hal_process_sess_evt_seq_changed(device, pkt);
break;
case HFI_EVENT_SESSION_PROPERTY_CHANGED:
- HAL_MSG_INFO("HFI_EVENT_SESSION_PROPERTY_CHANGED");
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
break;
default:
- HAL_MSG_INFO("hal_process_event_notify:unkown_event_id");
+ dprintk(VIDC_INFO, "hal_process_event_notify:unkown_event_id");
break;
}
}
@@ -177,9 +178,9 @@
int prop_id;
enum vidc_status status = VIDC_ERR_NONE;
- HAL_MSG_LOW("RECEIVED:SYS_INIT_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SYS_INIT_DONE");
if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) {
- HAL_MSG_ERROR("hal_process_sys_init_done:bad_pkt_size: %d",
+ dprintk(VIDC_ERR, "hal_process_sys_init_done:bad_pkt_size: %d",
pkt->size);
return;
}
@@ -188,7 +189,7 @@
if (!status) {
if (pkt->num_properties == 0) {
- HAL_MSG_ERROR("hal_process_sys_init_done:"
+ dprintk(VIDC_ERR, "hal_process_sys_init_done:"
"no_properties");
status = VIDC_ERR_FAIL;
goto err_no_prop;
@@ -198,7 +199,7 @@
hfi_msg_sys_init_done_packet) + sizeof(u32);
if (rem_bytes == 0) {
- HAL_MSG_ERROR("hal_process_sys_init_done:"
+ dprintk(VIDC_ERR, "hal_process_sys_init_done:"
"missing_prop_info");
status = VIDC_ERR_FAIL;
goto err_no_prop;
@@ -231,7 +232,7 @@
break;
}
default:
- HAL_MSG_ERROR("hal_process_sys_init_done:"
+ dprintk(VIDC_ERR, "hal_process_sys_init_done:"
"bad_prop_id");
status = VIDC_ERR_BAD_PARAM;
break;
@@ -259,11 +260,12 @@
enum vidc_status status = VIDC_ERR_NONE;
u32 pkt_size;
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- HAL_MSG_ERROR("RECEIVED:SYS_RELEASE_RESOURCE_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SYS_RELEASE_RESOURCE_DONE");
pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet);
if (pkt_size > pkt->size) {
- HAL_MSG_ERROR("hal_process_sys_rel_resource_done:bad size:%d",
- pkt->size);
+ dprintk(VIDC_ERR,
+ "hal_process_sys_rel_resource_done:bad size:%d",
+ pkt->size);
return;
}
status = vidc_map_hal_err_status((u32)pkt->error_type);
@@ -290,14 +292,15 @@
u32 req_bytes;
enum vidc_status rc = VIDC_ERR_NONE;
- HAL_MSG_LOW("Entered %s", __func__);
+ dprintk(VIDC_DBG, "Entered ");
req_bytes = prop->size - sizeof(
struct hfi_msg_session_property_info_packet);
if (req_bytes == 0 || (req_bytes % sizeof(
struct hfi_buffer_requirements))) {
- HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:bad_pkt_size:"
- " %d", req_bytes);
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_prop_buf_req:bad_pkt_size: %d",
+ req_bytes);
return;
}
@@ -309,11 +312,11 @@
buffer_count_actual)
|| (hfi_buf_req->buffer_alignment == 0)
|| (hfi_buf_req->buffer_size == 0)) {
- HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:"
+ dprintk(VIDC_ERR, "hal_process_sess_get_prop_buf_req:"
"bad_buf_req");
rc = VIDC_ERR_FAIL;
}
- HAL_MSG_LOW("got buffer requirements for: %d",
+ dprintk(VIDC_DBG, "got buffer requirements for: %d",
hfi_buf_req->buffer_type);
switch (hfi_buf_req->buffer_type) {
case HFI_BUFFER_INPUT:
@@ -362,8 +365,9 @@
HAL_BUFFER_INTERNAL_PERSIST;
break;
default:
- HAL_MSG_ERROR("%s: bad_buffer_type: %d",
- __func__, hfi_buf_req->buffer_type);
+ dprintk(VIDC_ERR,
+ "hal_process_sess_get_prop_buf_req: bad_buffer_type: %d",
+ hfi_buf_req->buffer_type);
break;
}
req_bytes -= sizeof(struct hfi_buffer_requirements);
@@ -377,15 +381,16 @@
struct msm_vidc_cb_cmd_done cmd_done;
struct buffer_requirements buff_req;
- HAL_MSG_INFO("Received SESSION_PROPERTY_INFO");
+ dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO");
if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
- HAL_MSG_ERROR("hal_process_session_prop_info:bad_pkt_size");
+ dprintk(VIDC_ERR, "hal_process_session_prop_info:bad_pkt_size");
return;
}
if (pkt->num_properties == 0) {
- HAL_MSG_ERROR("hal_process_session_prop_info:no_properties");
+ dprintk(VIDC_ERR,
+ "hal_process_session_prop_info:no_properties");
return;
}
@@ -404,7 +409,7 @@
device->callback(SESSION_PROPERTY_INFO, &cmd_done);
break;
default:
- HAL_MSG_ERROR("hal_process_session_prop_info:"
+ dprintk(VIDC_ERR, "hal_process_session_prop_info:"
"unknown_prop_id: %d",
pkt->rg_property_data[0]);
break;
@@ -417,10 +422,10 @@
struct msm_vidc_cb_cmd_done cmd_done;
struct vidc_hal_session_init_done session_init_done;
- HAL_MSG_LOW("RECEIVED:SESSION_INIT_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_INIT_DONE");
if (sizeof(struct hfi_msg_sys_session_init_done_packet)
> pkt->size) {
- HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+ dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
return;
}
@@ -445,11 +450,11 @@
struct hfi_msg_session_load_resources_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
- HAL_MSG_LOW("RECEIVED:SESSION_LOAD_RESOURCES_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_LOAD_RESOURCES_DONE");
if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
pkt->size) {
- HAL_MSG_ERROR("hal_process_session_load_res_done:"
+ dprintk(VIDC_ERR, "hal_process_session_load_res_done:"
" bad packet size: %d", pkt->size);
return;
}
@@ -470,10 +475,10 @@
{
struct msm_vidc_cb_cmd_done cmd_done;
- HAL_MSG_LOW("RECEIVED:SESSION_FLUSH_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_FLUSH_DONE");
if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
- HAL_MSG_ERROR("hal_process_session_flush_done: "
+ dprintk(VIDC_ERR, "hal_process_session_flush_done: "
"bad packet size: %d", pkt->size);
return;
}
@@ -493,11 +498,11 @@
{
struct msm_vidc_cb_data_done data_done;
- HAL_MSG_LOW("RECEIVED:SESSION_ETB_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_ETB_DONE");
if (!pkt || pkt->size !=
sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
- HAL_MSG_ERROR("hal_process_session_etb_done:bad_pkt_size");
+ dprintk(VIDC_ERR, "hal_process_session_etb_done:bad_pkt_size");
return;
}
@@ -525,13 +530,13 @@
struct hal_session *session;
if (!msg_hdr) {
- HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ dprintk(VIDC_ERR, "Invalid Params in ");
return;
}
session = (struct hal_session *)
((struct hal_session *) pack->session_id)->session_id;
- HAL_MSG_ERROR("RECEIVED:SESSION_FTB_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_FTB_DONE");
memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
@@ -542,11 +547,13 @@
if (sizeof(struct
hfi_msg_session_fill_buffer_done_compressed_packet)
!= pkt->size) {
- HAL_MSG_ERROR("%s: bad_pkt_size", __func__);
+ dprintk(VIDC_ERR,
+ "hal_process_session_ftb_done: bad_pkt_size");
return;
} else if (pkt->error_type != HFI_ERR_NONE) {
- HAL_MSG_ERROR("%s: got buffer back with error %x",
- __func__, pkt->error_type);
+ dprintk(VIDC_ERR,
+ "got buffer back with error %x",
+ pkt->error_type);
/* Proceed with the FBD */
}
@@ -570,6 +577,8 @@
data_done.output_done.packet_buffer1 = pkt->packet_buffer;
data_done.output_done.extra_data_buffer =
pkt->extra_data_buffer;
+ dprintk(VIDC_DBG, "FBD: Received buf: %p, of len: %d\n",
+ pkt->packet_buffer, pkt->filled_len);
} else if (is_decoder == 1) {
struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
(struct hfi_msg_session_fbd_uncompressed_plane0_packet *)
@@ -577,7 +586,7 @@
if (sizeof(struct
hfi_msg_session_fbd_uncompressed_plane0_packet)
> pkt->size) {
- HAL_MSG_ERROR("hal_process_session_ftb_done:"
+ dprintk(VIDC_ERR, "hal_process_session_ftb_done:"
"bad_pkt_size");
return;
}
@@ -623,11 +632,11 @@
{
struct msm_vidc_cb_cmd_done cmd_done;
- HAL_MSG_LOW("RECEIVED:SESSION_START_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_START_DONE");
if (!pkt || pkt->size !=
sizeof(struct hfi_msg_session_start_done_packet)) {
- HAL_MSG_ERROR("hal_process_session_start_done:"
+ dprintk(VIDC_ERR, "hal_process_session_start_done:"
"bad packet/packet size: %d", pkt->size);
return;
}
@@ -647,11 +656,11 @@
{
struct msm_vidc_cb_cmd_done cmd_done;
- HAL_MSG_LOW("RECEIVED:SESSION_STOP_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_STOP_DONE");
if (!pkt || pkt->size !=
sizeof(struct hfi_msg_session_stop_done_packet)) {
- HAL_MSG_ERROR("hal_process_session_stop_done:"
+ dprintk(VIDC_ERR, "hal_process_session_stop_done:"
"bad packet/packet size: %d", pkt->size);
return;
}
@@ -671,11 +680,11 @@
{
struct msm_vidc_cb_cmd_done cmd_done;
- HAL_MSG_LOW("RECEIVED:SESSION_RELEASE_RESOURCES_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_RESOURCES_DONE");
if (!pkt || pkt->size !=
sizeof(struct hfi_msg_session_release_resources_done_packet)) {
- HAL_MSG_ERROR("hal_process_session_rel_res_done:"
+ dprintk(VIDC_ERR, "hal_process_session_rel_res_done:"
"bad packet/packet size: %d", pkt->size);
return;
}
@@ -697,18 +706,18 @@
struct list_head *curr, *next;
struct hal_session *sess_close;
- HAL_MSG_LOW("RECEIVED:SESSION_END_DONE");
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_END_DONE");
if (!pkt || pkt->size !=
sizeof(struct hfi_msg_sys_session_end_done_packet)) {
- HAL_MSG_ERROR("hal_process_session_end_done: "
+ dprintk(VIDC_ERR, "hal_process_session_end_done: "
"bad packet/packet size: %d", pkt->size);
return;
}
list_for_each_safe(curr, next, &device->sess_head) {
sess_close = list_entry(curr, struct hal_session, list);
- HAL_MSG_MEDIUM("deleted the session: 0x%x",
+ dprintk(VIDC_INFO, "deleted the session: 0x%x",
sess_close->session_id);
list_del(&sess_close->list);
kfree(sess_close);
@@ -724,18 +733,40 @@
device->callback(SESSION_END_DONE, &cmd_done);
}
+static void hal_process_session_get_seq_hdr_done(struct hal_device *device,
+ struct hfi_msg_session_get_sequence_header_done_packet *pkt)
+{
+ struct msm_vidc_cb_data_done data_done;
+ if (!pkt || pkt->size !=
+ sizeof(struct
+ hfi_msg_session_get_sequence_header_done_packet)) {
+ dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+ memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
+ data_done.device_id = device->device_id;
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ data_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ data_done.output_done.packet_buffer1 = pkt->sequence_header;
+ data_done.output_done.filled_len1 = pkt->header_len;
+ dprintk(VIDC_INFO, "seq_hdr: %p, Length: %d",
+ pkt->sequence_header, pkt->header_len);
+ device->callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
+}
+
static void hal_process_msg_packet(struct hal_device *device,
struct vidc_hal_msg_pkt_hdr *msg_hdr)
{
if (!device || !msg_hdr || msg_hdr->size <
VIDC_IFACEQ_MIN_PKT_SIZE) {
- HAL_MSG_ERROR("hal_process_msg_packet:bad"
+ dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
"packet/packet size: %d", msg_hdr->size);
return;
}
- HAL_MSG_ERROR("Received: 0x%x in %s", msg_hdr->packet, __func__);
-
+ dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
switch (msg_hdr->packet) {
case HFI_MSG_EVENT_NOTIFY:
hal_process_event_notify(device,
@@ -799,8 +830,13 @@
(struct hfi_msg_sys_release_resource_done_packet *)
msg_hdr);
break;
+ case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+ hal_process_session_get_seq_hdr_done(device, (struct
+ hfi_msg_session_get_sequence_header_done_packet
+ *) msg_hdr);
+ break;
default:
- HAL_MSG_ERROR("UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
+ dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
}
}
@@ -809,13 +845,13 @@
{
u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
- HAL_MSG_INFO("############vidc_hal_response_handler\n");
+ dprintk(VIDC_INFO, "#####vidc_hal_response_handler#####\n");
if (device) {
while (!vidc_hal_iface_msgq_read(device, packet)) {
hal_process_msg_packet(device,
(struct vidc_hal_msg_pkt_hdr *) packet);
}
} else {
- HAL_MSG_ERROR("SPURIOUS_INTERRUPT");
+ dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
}
}
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 232c202..8981c1a 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -153,7 +153,7 @@
bool secure, struct mem_region *mregion)
{
struct ion_handle *handle;
- void *kvaddr, *phys_addr;
+ void *kvaddr = NULL, *phys_addr = NULL;
unsigned long size;
unsigned int alloc_regions = 0;
int rc;
@@ -209,7 +209,9 @@
return rc;
alloc_fail:
if (!IS_ERR_OR_NULL(handle)) {
- ion_unmap_kernel(client, handle);
+ if (!IS_ERR_OR_NULL(kvaddr))
+ ion_unmap_kernel(client, handle);
+
ion_free(client, handle);
mregion->kvaddr = NULL;
@@ -1308,7 +1310,10 @@
WFD_MSG_DBG("wfd_open: E\n");
wfd_dev = video_drvdata(filp);
-
+ if (!wfd_dev) {
+ rc = -EINVAL;
+ goto err_dev_busy;
+ }
mutex_lock(&wfd_dev->dev_lock);
if (wfd_dev->in_use) {
WFD_MSG_ERR("Device already in use.\n");
@@ -1321,7 +1326,7 @@
mutex_unlock(&wfd_dev->dev_lock);
inst = kzalloc(sizeof(struct wfd_inst), GFP_KERNEL);
- if (!inst || !wfd_dev) {
+ if (!inst) {
WFD_MSG_ERR("Could not allocate memory for "
"wfd instance\n");
rc = -ENOMEM;
@@ -1379,6 +1384,9 @@
v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
err_mdp_open:
+ mutex_lock(&wfd_dev->dev_lock);
+ wfd_dev->in_use = false;
+ mutex_unlock(&wfd_dev->dev_lock);
kfree(inst);
err_dev_busy:
return rc;
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 7e59c98..1ff4468 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -32,7 +32,6 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h> /* kfree, kzalloc */
#include <linux/gpio.h>
-
#include <mach/dma.h>
#include <mach/msm_tsif.h>
@@ -273,36 +272,6 @@
/* ===clocks end=== */
/* ===gpio begin=== */
-static void tsif_gpios_free(const struct msm_gpio *table, int size)
-{
- int i;
- const struct msm_gpio *g;
- for (i = size-1; i >= 0; i--) {
- g = table + i;
- gpio_free(GPIO_PIN(g->gpio_cfg));
- }
-}
-
-static int tsif_gpios_request(const struct msm_gpio *table, int size)
-{
- int rc;
- int i;
- const struct msm_gpio *g;
- for (i = 0; i < size; i++) {
- g = table + i;
- rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
- if (rc) {
- pr_err("gpio_request(%d) <%s> failed: %d\n",
- GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
- goto err;
- }
- }
- return 0;
-err:
- tsif_gpios_free(table, i);
- return rc;
-}
-
static int tsif_gpios_disable(const struct msm_gpio *table, int size)
{
int rc = 0;
@@ -357,19 +326,14 @@
static int tsif_gpios_request_enable(const struct msm_gpio *table, int size)
{
- int rc = tsif_gpios_request(table, size);
- if (rc)
- return rc;
+ int rc;
rc = tsif_gpios_enable(table, size);
- if (rc)
- tsif_gpios_free(table, size);
return rc;
}
static void tsif_gpios_disable_free(const struct msm_gpio *table, int size)
{
tsif_gpios_disable(table, size);
- tsif_gpios_free(table, size);
}
static int tsif_start_gpios(struct msm_tsif_device *tsif_device)
@@ -1029,6 +993,7 @@
struct msm_tsif_platform_data *pdata =
tsif_device->pdev->dev.platform_data;
+
dev_info(&tsif_device->pdev->dev, "%s\n", __func__);
if (tsif_device->state != tsif_state_stopped)
return -EAGAIN;
@@ -1039,14 +1004,6 @@
}
tsif_device->state = tsif_state_running;
- /* make sure the GPIO's are set up */
- rc = tsif_start_gpios(tsif_device);
- if (rc) {
- dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
- tsif_dma_exit(tsif_device);
- return rc;
- }
-
/*
* DMA should be scheduled prior to TSIF hardware initialization,
* otherwise "bus error" will be reported by Data Mover
@@ -1062,9 +1019,20 @@
rc = tsif_start_hw(tsif_device);
if (rc) {
dev_err(&tsif_device->pdev->dev, "Unable to start HW\n");
- tsif_stop_gpios(tsif_device);
tsif_dma_exit(tsif_device);
tsif_clock(tsif_device, 0);
+ disable_irq(tsif_device->irq);
+ return rc;
+ }
+
+ /* make sure the GPIO's are set up */
+ rc = tsif_start_gpios(tsif_device);
+ if (rc) {
+ dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
+ tsif_stop_hw(tsif_device);
+ tsif_dma_exit(tsif_device);
+ tsif_clock(tsif_device, 0);
+ disable_irq(tsif_device->irq);
return rc;
}
@@ -1073,11 +1041,16 @@
dev_err(&tsif_device->pdev->dev,
"Runtime PM: Unable to wake up the device, rc = %d\n",
result);
+ tsif_stop_gpios(tsif_device);
+ tsif_stop_hw(tsif_device);
+ tsif_dma_exit(tsif_device);
+ tsif_clock(tsif_device, 0);
+ disable_irq(tsif_device->irq);
return result;
}
wake_lock(&tsif_device->wake_lock);
- return rc;
+ return 0;
}
static int action_close(struct msm_tsif_device *tsif_device)
@@ -1094,7 +1067,7 @@
* there are any outstanding reads on the bus, and if we
* stop the TSIF too quickly, it can cause a bus error.
*/
- msleep(100);
+ msleep(250);
/* now we can stop the core */
tsif_stop_hw(tsif_device);
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
index 095cb4d..3fced2d 100644
--- a/drivers/net/ethernet/msm/Kconfig
+++ b/drivers/net/ethernet/msm/Kconfig
@@ -18,7 +18,7 @@
config MSM_RMNET_BAM
bool "RMNET BAM Driver"
- depends on MSM_BAM_DMUX
+ depends on (MSM_BAM_DMUX && NET_SCHED && NET_SCH_HTB && NET_SCH_PRIO && NET_CLS_FW)
default n
help
Implements RMNET over BAM interface.
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 914f4fb..9b8ab39 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -295,7 +295,7 @@
config WCNSS_CORE
tristate "Qualcomm WCNSS CORE driver"
- depends on ARCH_MSM8960
+ depends on (ARCH_MSM8960 || ARCH_MSM8974)
select WIRELESS_EXT
select WEXT_PRIV
select WEXT_CORE
@@ -303,6 +303,12 @@
---help---
Core driver for the Qualcomm WCNSS triple play connectivity subsystem
+config WCNSS_CORE_PRONTO
+ tristate "Qualcomm WCNSS Pronto Support"
+ depends on WCNSS_CORE
+ ---help---
+ Pronto Support for the Qualcomm WCNSS triple play connectivity subsystem
+
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
diff --git a/drivers/net/wireless/wcnss/Makefile b/drivers/net/wireless/wcnss/Makefile
index c077848..11fa673 100644
--- a/drivers/net/wireless/wcnss/Makefile
+++ b/drivers/net/wireless/wcnss/Makefile
@@ -1,6 +1,6 @@
# Makefile for WCNSS triple-play driver
-wcnsscore-objs += wcnss_wlan.o wcnss_riva.o qcomwlan_secif.o
+wcnsscore-objs += wcnss_wlan.o qcomwlan_secif.o wcnss_vreg.o
obj-$(CONFIG_WCNSS_CORE) += wcnsscore.o
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
deleted file mode 100644
index 2d9ad82..0000000
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/pm8xxx/gpio.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/semaphore.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <mach/msm_xo.h>
-#include <mach/msm_iomap.h>
-
-
-static void __iomem *msm_riva_base;
-static struct msm_xo_voter *wlan_clock;
-static const char *id = "WLAN";
-static LIST_HEAD(power_on_lock_list);
-static DEFINE_MUTEX(list_lock);
-static DEFINE_SEMAPHORE(riva_power_on_lock);
-
-#define MSM_RIVA_PHYS 0x03204000
-#define RIVA_PMU_CFG (msm_riva_base + 0x28)
-#define RIVA_PMU_CFG_IRIS_XO_CFG BIT(3)
-#define RIVA_PMU_CFG_IRIS_XO_EN BIT(4)
-#define RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5)
-#define RIVA_PMU_CFG_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
-
-#define RIVA_PMU_CFG_IRIS_XO_MODE 0x6
-#define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
-
-#define VREG_NULL_CONFIG 0x0000
-#define VREG_GET_REGULATOR_MASK 0x0001
-#define VREG_SET_VOLTAGE_MASK 0x0002
-#define VREG_OPTIMUM_MODE_MASK 0x0004
-#define VREG_ENABLE_MASK 0x0008
-
-struct vregs_info {
- const char * const name;
- int state;
- const int nominal_min;
- const int low_power_min;
- const int max_voltage;
- const int uA_load;
- struct regulator *regulator;
-};
-
-static struct vregs_info iris_vregs[] = {
- {"iris_vddxo", VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000, NULL},
- {"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
- {"iris_vddpa", VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
- {"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000, NULL},
-};
-
-static struct vregs_info riva_vregs[] = {
- {"riva_vddmx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
- {"riva_vddcx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
- {"riva_vddpx", VREG_NULL_CONFIG, 1800000, 0, 1800000, 0, NULL},
-};
-
-struct host_driver {
- char name[20];
- struct list_head list;
-};
-
-
-static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
-{
- u32 reg = 0;
- int rc = 0;
- struct clk *cxo = clk_get(dev, "cxo");
- if (IS_ERR(cxo)) {
- pr_err("Couldn't get cxo clock\n");
- return PTR_ERR(cxo);
- }
-
- if (on) {
- msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
- if (!msm_riva_base) {
- pr_err("ioremap MSM_RIVA_PHYS failed\n");
- goto fail;
- }
-
- /* Enable IRIS XO */
- rc = clk_prepare_enable(cxo);
- if (rc) {
- pr_err("cxo enable failed\n");
- goto fail;
- }
- writel_relaxed(0, RIVA_PMU_CFG);
- reg = readl_relaxed(RIVA_PMU_CFG);
- reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
- RIVA_PMU_CFG_IRIS_XO_EN;
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
- reg &= ~(RIVA_PMU_CFG_IRIS_XO_MODE);
-
- if (use_48mhz_xo)
- reg |= RIVA_PMU_CFG_IRIS_XO_MODE_48;
-
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Start IRIS XO configuration */
- reg |= RIVA_PMU_CFG_IRIS_XO_CFG;
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Wait for XO configuration to finish */
- while (readl_relaxed(RIVA_PMU_CFG) &
- RIVA_PMU_CFG_IRIS_XO_CFG_STS)
- cpu_relax();
-
- /* Stop IRIS XO configuration */
- reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
- RIVA_PMU_CFG_IRIS_XO_CFG);
- writel_relaxed(reg, RIVA_PMU_CFG);
- clk_disable_unprepare(cxo);
-
- if (!use_48mhz_xo) {
- wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
- if (IS_ERR(wlan_clock)) {
- rc = PTR_ERR(wlan_clock);
- pr_err("Failed to get MSM_XO_TCXO_A2 voter"
- " (%d)\n", rc);
- goto fail;
- }
-
- rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
- if (rc < 0) {
- pr_err("Configuring MSM_XO_MODE_ON failed"
- " (%d)\n", rc);
- goto msm_xo_vote_fail;
- }
- }
- } else {
- if (wlan_clock != NULL && !use_48mhz_xo) {
- rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
- if (rc < 0)
- pr_err("Configuring MSM_XO_MODE_OFF failed"
- " (%d)\n", rc);
- }
- }
-
- /* Add some delay for XO to settle */
- msleep(20);
-
- clk_put(cxo);
- return rc;
-
-msm_xo_vote_fail:
- msm_xo_put(wlan_clock);
-
-fail:
- clk_put(cxo);
- return rc;
-}
-
-/* Helper routine to turn off all WCNSS vregs e.g. IRIS, Riva */
-static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
-{
- int i, rc = 0;
-
- /* Regulators need to be turned off in the reverse order */
- for (i = (size-1); i >= 0; i--) {
- if (regulators[i].state == VREG_NULL_CONFIG)
- continue;
-
- /* Remove PWM mode */
- if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
- rc = regulator_set_optimum_mode(
- regulators[i].regulator, 0);
- if (rc < 0)
- pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
- regulators[i].name, rc);
- }
-
- /* Set voltage to lowest level */
- if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
- rc = regulator_set_voltage(regulators[i].regulator,
- regulators[i].low_power_min,
- regulators[i].max_voltage);
- if (rc)
- pr_err("regulator_set_voltage(%s) failed (%d)\n",
- regulators[i].name, rc);
- }
-
- /* Disable regulator */
- if (regulators[i].state & VREG_ENABLE_MASK) {
- rc = regulator_disable(regulators[i].regulator);
- if (rc < 0)
- pr_err("vreg %s disable failed (%d)\n",
- regulators[i].name, rc);
- }
-
- /* Free the regulator source */
- if (regulators[i].state & VREG_GET_REGULATOR_MASK)
- regulator_put(regulators[i].regulator);
-
- regulators[i].state = VREG_NULL_CONFIG;
- }
-}
-
-/* Common helper routine to turn on all WCNSS vregs e.g. IRIS, Riva */
-static int wcnss_vregs_on(struct device *dev,
- struct vregs_info regulators[], uint size)
-{
- int i, rc = 0, reg_cnt;
-
- for (i = 0; i < size; i++) {
- /* Get regulator source */
- regulators[i].regulator =
- regulator_get(dev, regulators[i].name);
- if (IS_ERR(regulators[i].regulator)) {
- rc = PTR_ERR(regulators[i].regulator);
- pr_err("regulator get of %s failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_GET_REGULATOR_MASK;
- reg_cnt = regulator_count_voltages(regulators[i].regulator);
- /* Set voltage to nominal. Exclude swtiches e.g. LVS */
- if ((regulators[i].nominal_min || regulators[i].max_voltage)
- && (reg_cnt > 0)) {
- rc = regulator_set_voltage(regulators[i].regulator,
- regulators[i].nominal_min,
- regulators[i].max_voltage);
- if (rc) {
- pr_err("regulator_set_voltage(%s) failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_SET_VOLTAGE_MASK;
- }
-
- /* Vote for PWM/PFM mode if needed */
- if (regulators[i].uA_load && (reg_cnt > 0)) {
- rc = regulator_set_optimum_mode(regulators[i].regulator,
- regulators[i].uA_load);
- if (rc < 0) {
- pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
- }
-
- /* Enable the regulator */
- rc = regulator_enable(regulators[i].regulator);
- if (rc) {
- pr_err("vreg %s enable failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_ENABLE_MASK;
- }
-
- return rc;
-
-fail:
- wcnss_vregs_off(regulators, size);
- return rc;
-
-}
-
-static void wcnss_iris_vregs_off(void)
-{
- wcnss_vregs_off(iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static int wcnss_iris_vregs_on(struct device *dev)
-{
- return wcnss_vregs_on(dev, iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static void wcnss_riva_vregs_off(void)
-{
- wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-static int wcnss_riva_vregs_on(struct device *dev)
-{
- return wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-int wcnss_wlan_power(struct device *dev,
- struct wcnss_wlan_config *cfg,
- enum wcnss_opcode on)
-{
- int rc = 0;
-
- if (on) {
- down(&riva_power_on_lock);
- /* RIVA regulator settings */
- rc = wcnss_riva_vregs_on(dev);
- if (rc)
- goto fail_riva_on;
-
- /* IRIS regulator settings */
- rc = wcnss_iris_vregs_on(dev);
- if (rc)
- goto fail_iris_on;
-
- /* Configure IRIS XO */
- rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
- WCNSS_WLAN_SWITCH_ON);
- if (rc)
- goto fail_iris_xo;
- up(&riva_power_on_lock);
-
- } else {
- configure_iris_xo(dev, cfg->use_48mhz_xo,
- WCNSS_WLAN_SWITCH_OFF);
- wcnss_iris_vregs_off();
- wcnss_riva_vregs_off();
- }
-
- return rc;
-
-fail_iris_xo:
- wcnss_iris_vregs_off();
-
-fail_iris_on:
- wcnss_riva_vregs_off();
-
-fail_riva_on:
- up(&riva_power_on_lock);
- return rc;
-}
-EXPORT_SYMBOL(wcnss_wlan_power);
-
-/*
- * During SSR Riva should not be 'powered on' until all the host drivers
- * finish their shutdown routines. Host drivers use below APIs to
- * synchronize power-on. Riva will not be 'powered on' until all the
- * requests(to lock power-on) are freed.
- */
-int req_riva_power_on_lock(char *driver_name)
-{
- struct host_driver *node;
-
- if (!driver_name)
- goto err;
-
- node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
- if (!node)
- goto err;
- strncpy(node->name, driver_name, sizeof(node->name));
-
- mutex_lock(&list_lock);
- /* Lock when the first request is added */
- if (list_empty(&power_on_lock_list))
- down(&riva_power_on_lock);
- list_add(&node->list, &power_on_lock_list);
- mutex_unlock(&list_lock);
-
- return 0;
-
-err:
- return -EINVAL;
-}
-EXPORT_SYMBOL(req_riva_power_on_lock);
-
-int free_riva_power_on_lock(char *driver_name)
-{
- int ret = -1;
- struct host_driver *node;
-
- mutex_lock(&list_lock);
- list_for_each_entry(node, &power_on_lock_list, list) {
- if (!strncmp(node->name, driver_name, sizeof(node->name))) {
- list_del(&node->list);
- kfree(node);
- ret = 0;
- break;
- }
- }
- /* unlock when the last host driver frees the lock */
- if (list_empty(&power_on_lock_list))
- up(&riva_power_on_lock);
- mutex_unlock(&list_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(free_riva_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
new file mode 100644
index 0000000..01b27dd
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/wcnss_wlan.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <mach/msm_xo.h>
+#include <mach/msm_iomap.h>
+
+
+static void __iomem *msm_wcnss_base;
+static struct msm_xo_voter *wlan_clock;
+static const char *id = "WLAN";
+static LIST_HEAD(power_on_lock_list);
+static DEFINE_MUTEX(list_lock);
+static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+
+#define MSM_RIVA_PHYS 0x03204000
+#define MSM_PRONTO_PHYS 0xfb21b000
+
+#define RIVA_PMU_OFFSET 0x28
+#define PRONTO_PMU_OFFSET 0x1004
+
+#define WCNSS_PMU_CFG_IRIS_XO_CFG BIT(3)
+#define WCNSS_PMU_CFG_IRIS_XO_EN BIT(4)
+#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5)
+#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_CFG_IRIS_XO_MODE 0x6
+#define WCNSS_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
+
+#define VREG_NULL_CONFIG 0x0000
+#define VREG_GET_REGULATOR_MASK 0x0001
+#define VREG_SET_VOLTAGE_MASK 0x0002
+#define VREG_OPTIMUM_MODE_MASK 0x0004
+#define VREG_ENABLE_MASK 0x0008
+
+struct vregs_info {
+ const char * const name;
+ int state;
+ const int nominal_min;
+ const int low_power_min;
+ const int max_voltage;
+ const int uA_load;
+ struct regulator *regulator;
+};
+
+/* IRIS regulators for Riva hardware */
+static struct vregs_info iris_vregs_riva[] = {
+ {"iris_vddxo", VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000, NULL},
+ {"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
+ {"iris_vddpa", VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
+ {"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000, NULL},
+};
+
+/* WCNSS regulators for Riva hardware */
+static struct vregs_info riva_vregs[] = {
+ /* Riva */
+ {"riva_vddmx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
+ {"riva_vddcx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
+ {"riva_vddpx", VREG_NULL_CONFIG, 1800000, 0, 1800000, 0, NULL},
+};
+
+/* IRIS regulators for Pronto hardware */
+static struct vregs_info iris_vregs_pronto[] = {
+ {"qcom,iris-vddxo", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 10000, NULL},
+ {"qcom,iris-vddrfa", VREG_NULL_CONFIG, 1300000, 0,
+ 1300000, 100000, NULL},
+ {"qcom,iris-vddpa", VREG_NULL_CONFIG, 2900000, 0,
+ 3000000, 515000, NULL},
+ {"qcom,iris-vdddig", VREG_NULL_CONFIG, 1225000, 0,
+ 1225000, 10000, NULL},
+};
+
+/* WCNSS regulators for Pronto hardware */
+static struct vregs_info pronto_vregs[] = {
+ {"qcom,pronto-vddmx", VREG_NULL_CONFIG, 950000, 0,
+ 1150000, 0, NULL},
+ {"qcom,pronto-vddcx", VREG_NULL_CONFIG, 900000, 0,
+ 1150000, 0, NULL},
+ {"qcom,pronto-vddpx", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 0, NULL},
+};
+
+
+struct host_driver {
+ char name[20];
+ struct list_head list;
+};
+
+
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
+{
+ u32 reg = 0;
+ int rc = 0;
+ int size = 0;
+ int pmu_offset = 0;
+ unsigned long wcnss_phys_addr;
+ void __iomem *pmu_conf_reg;
+ struct clk *clk;
+
+ if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
+ wcnss_phys_addr = MSM_PRONTO_PHYS;
+ pmu_offset = PRONTO_PMU_OFFSET;
+ size = 0x3000;
+
+ clk = clk_get(dev, "xo");
+ if (IS_ERR(clk)) {
+ pr_err("Couldn't get xo clock\n");
+ return PTR_ERR(clk);
+ }
+ } else {
+ wcnss_phys_addr = MSM_RIVA_PHYS;
+ pmu_offset = RIVA_PMU_OFFSET;
+ size = SZ_256;
+
+ clk = clk_get(dev, "cxo");
+ if (IS_ERR(clk)) {
+ pr_err("Couldn't get cxo clock\n");
+ return PTR_ERR(clk);
+ }
+ }
+
+ if (on) {
+ msm_wcnss_base = ioremap(wcnss_phys_addr, size);
+ if (!msm_wcnss_base) {
+ pr_err("ioremap wcnss physical failed\n");
+ goto fail;
+ }
+ pmu_conf_reg = msm_wcnss_base + pmu_offset;
+
+ /* Enable IRIS XO */
+ rc = clk_prepare_enable(clk);
+ if (rc) {
+ pr_err("clk enable failed\n");
+ goto fail;
+ }
+ writel_relaxed(0, pmu_conf_reg);
+ reg = readl_relaxed(pmu_conf_reg);
+ reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+ WCNSS_PMU_CFG_IRIS_XO_EN;
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
+ reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
+
+ if (use_48mhz_xo)
+ reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
+
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Start IRIS XO configuration */
+ reg |= WCNSS_PMU_CFG_IRIS_XO_CFG;
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Wait for XO configuration to finish */
+ while (readl_relaxed(pmu_conf_reg) &
+ WCNSS_PMU_CFG_IRIS_XO_CFG_STS)
+ cpu_relax();
+
+ /* Stop IRIS XO configuration */
+ reg &= ~(WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+ WCNSS_PMU_CFG_IRIS_XO_CFG);
+ writel_relaxed(reg, pmu_conf_reg);
+ clk_disable_unprepare(clk);
+
+ if (!use_48mhz_xo) {
+ wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
+ if (IS_ERR(wlan_clock)) {
+ rc = PTR_ERR(wlan_clock);
+ pr_err("Failed to get MSM_XO_TCXO_A2 voter (%d)\n",
+ rc);
+ goto fail;
+ }
+
+ rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
+ if (rc < 0) {
+ pr_err("Configuring MSM_XO_MODE_ON failed (%d)\n",
+ rc);
+ goto msm_xo_vote_fail;
+ }
+ }
+ } else {
+ if (wlan_clock != NULL && !use_48mhz_xo) {
+ rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
+ if (rc < 0)
+ pr_err("Configuring MSM_XO_MODE_OFF failed (%d)\n",
+ rc);
+ }
+ }
+
+ /* Add some delay for XO to settle */
+ msleep(20);
+
+ clk_put(clk);
+ return rc;
+
+msm_xo_vote_fail:
+ msm_xo_put(wlan_clock);
+
+fail:
+ clk_put(clk);
+ return rc;
+}
+
+/* Helper routine to turn off all WCNSS & IRIS vregs */
+static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
+{
+ int i, rc = 0;
+
+ /* Regulators need to be turned off in the reverse order */
+ for (i = (size-1); i >= 0; i--) {
+ if (regulators[i].state == VREG_NULL_CONFIG)
+ continue;
+
+ /* Remove PWM mode */
+ if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
+ rc = regulator_set_optimum_mode(
+ regulators[i].regulator, 0);
+ if (rc < 0)
+ pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ }
+
+ /* Set voltage to lowest level */
+ if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
+ rc = regulator_set_voltage(regulators[i].regulator,
+ regulators[i].low_power_min,
+ regulators[i].max_voltage);
+ if (rc)
+ pr_err("regulator_set_voltage(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ }
+
+ /* Disable regulator */
+ if (regulators[i].state & VREG_ENABLE_MASK) {
+ rc = regulator_disable(regulators[i].regulator);
+ if (rc < 0)
+ pr_err("vreg %s disable failed (%d)\n",
+ regulators[i].name, rc);
+ }
+
+ /* Free the regulator source */
+ if (regulators[i].state & VREG_GET_REGULATOR_MASK)
+ regulator_put(regulators[i].regulator);
+
+ regulators[i].state = VREG_NULL_CONFIG;
+ }
+}
+
+/* Common helper routine to turn on all WCNSS & IRIS vregs */
+static int wcnss_vregs_on(struct device *dev,
+ struct vregs_info regulators[], uint size)
+{
+ int i, rc = 0, reg_cnt;
+
+ for (i = 0; i < size; i++) {
+ /* Get regulator source */
+ regulators[i].regulator =
+ regulator_get(dev, regulators[i].name);
+ if (IS_ERR(regulators[i].regulator)) {
+ rc = PTR_ERR(regulators[i].regulator);
+ pr_err("regulator get of %s failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_GET_REGULATOR_MASK;
+ reg_cnt = regulator_count_voltages(regulators[i].regulator);
+ /* Set voltage to nominal. Exclude swtiches e.g. LVS */
+ if ((regulators[i].nominal_min || regulators[i].max_voltage)
+ && (reg_cnt > 0)) {
+ rc = regulator_set_voltage(regulators[i].regulator,
+ regulators[i].nominal_min,
+ regulators[i].max_voltage);
+ if (rc) {
+ pr_err("regulator_set_voltage(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_SET_VOLTAGE_MASK;
+ }
+
+ /* Vote for PWM/PFM mode if needed */
+ if (regulators[i].uA_load && (reg_cnt > 0)) {
+ rc = regulator_set_optimum_mode(regulators[i].regulator,
+ regulators[i].uA_load);
+ if (rc < 0) {
+ pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
+ }
+
+ /* Enable the regulator */
+ rc = regulator_enable(regulators[i].regulator);
+ if (rc) {
+ pr_err("vreg %s enable failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_ENABLE_MASK;
+ }
+
+ return rc;
+
+fail:
+ wcnss_vregs_off(regulators, size);
+ return rc;
+
+}
+
+static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type)
+{
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ wcnss_vregs_off(iris_vregs_riva, ARRAY_SIZE(iris_vregs_riva));
+ break;
+ case WCNSS_PRONTO_HW:
+ wcnss_vregs_off(iris_vregs_pronto,
+ ARRAY_SIZE(iris_vregs_pronto));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+
+ }
+}
+
+static int wcnss_iris_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+ int ret = -1;
+
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ ret = wcnss_vregs_on(dev, iris_vregs_riva,
+ ARRAY_SIZE(iris_vregs_riva));
+ break;
+ case WCNSS_PRONTO_HW:
+ ret = wcnss_vregs_on(dev, iris_vregs_pronto,
+ ARRAY_SIZE(iris_vregs_pronto));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ }
+ return ret;
+}
+
+static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type)
+{
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
+ break;
+ case WCNSS_PRONTO_HW:
+ wcnss_vregs_off(pronto_vregs, ARRAY_SIZE(pronto_vregs));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ }
+
+}
+
+static int wcnss_core_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+ int ret = -1;
+
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ ret = wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
+ break;
+ case WCNSS_PRONTO_HW:
+ ret = wcnss_vregs_on(dev, pronto_vregs,
+ ARRAY_SIZE(pronto_vregs));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ }
+
+ return ret;
+
+}
+
+int wcnss_wlan_power(struct device *dev,
+ struct wcnss_wlan_config *cfg,
+ enum wcnss_opcode on)
+{
+ int rc = 0;
+ enum wcnss_hw_type hw_type = wcnss_hardware_type();
+
+ if (on) {
+ down(&wcnss_power_on_lock);
+ /* RIVA regulator settings */
+ rc = wcnss_core_vregs_on(dev, hw_type);
+ if (rc)
+ goto fail_wcnss_on;
+
+ /* IRIS regulator settings */
+ rc = wcnss_iris_vregs_on(dev, hw_type);
+ if (rc)
+ goto fail_iris_on;
+
+ /* Configure IRIS XO */
+ rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+ WCNSS_WLAN_SWITCH_ON);
+ if (rc)
+ goto fail_iris_xo;
+ up(&wcnss_power_on_lock);
+
+ } else {
+ configure_iris_xo(dev, cfg->use_48mhz_xo,
+ WCNSS_WLAN_SWITCH_OFF);
+ wcnss_iris_vregs_off(hw_type);
+ wcnss_core_vregs_off(hw_type);
+ }
+
+ return rc;
+
+fail_iris_xo:
+ wcnss_iris_vregs_off(hw_type);
+
+fail_iris_on:
+ wcnss_core_vregs_off(hw_type);
+
+fail_wcnss_on:
+ up(&wcnss_power_on_lock);
+ return rc;
+}
+EXPORT_SYMBOL(wcnss_wlan_power);
+
+/*
+ * During SSR WCNSS should not be 'powered on' until all the host drivers
+ * finish their shutdown routines. Host drivers use below APIs to
+ * synchronize power-on. WCNSS will not be 'powered on' until all the
+ * requests(to lock power-on) are freed.
+ */
+int wcnss_req_power_on_lock(char *driver_name)
+{
+ struct host_driver *node;
+
+ if (!driver_name)
+ goto err;
+
+ node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
+ if (!node)
+ goto err;
+ strlcpy(node->name, driver_name, sizeof(node->name));
+
+ mutex_lock(&list_lock);
+ /* Lock when the first request is added */
+ if (list_empty(&power_on_lock_list))
+ down(&wcnss_power_on_lock);
+ list_add(&node->list, &power_on_lock_list);
+ mutex_unlock(&list_lock);
+
+ return 0;
+
+err:
+ return -EINVAL;
+}
+EXPORT_SYMBOL(wcnss_req_power_on_lock);
+
+int wcnss_free_power_on_lock(char *driver_name)
+{
+ int ret = -1;
+ struct host_driver *node;
+
+ mutex_lock(&list_lock);
+ list_for_each_entry(node, &power_on_lock_list, list) {
+ if (!strncmp(node->name, driver_name, sizeof(node->name))) {
+ list_del(&node->list);
+ kfree(node);
+ ret = 0;
+ break;
+ }
+ }
+ /* unlock when the last host driver frees the lock */
+ if (list_empty(&power_on_lock_list))
+ up(&wcnss_power_on_lock);
+ mutex_unlock(&list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(wcnss_free_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 633809a..e83b195 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -23,6 +23,8 @@
#include <linux/gpio.h>
#include <linux/wakelock.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <mach/peripheral-loader.h>
#include <mach/msm_smd.h>
@@ -76,6 +78,7 @@
unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned int serial_number;
int thermal_mitigation;
+ enum wcnss_hw_type wcnss_hw_type;
void (*tm_notify)(struct device *, int);
struct wcnss_wlan_config wlan_config;
struct delayed_work wcnss_work;
@@ -225,11 +228,42 @@
static void wcnss_post_bootup(struct work_struct *work)
{
- pr_info("%s: Cancel APPS vote for Iris & Riva\n", __func__);
+ pr_info("%s: Cancel APPS vote for Iris & WCNSS\n", __func__);
- /* Since Riva is up, cancel any APPS vote for Iris & Riva VREGs */
+ /* Since WCNSS is up, cancel any APPS vote for Iris & WCNSS VREGs */
wcnss_wlan_power(&penv->pdev->dev, &penv->wlan_config,
WCNSS_WLAN_SWITCH_OFF);
+
+}
+
+static int
+wcnss_pronto_gpios_config(struct device *dev, bool enable)
+{
+ int rc = 0;
+ int i, j;
+ int WCNSS_WLAN_NUM_GPIOS = 5;
+
+ for (i = 0; i < WCNSS_WLAN_NUM_GPIOS; i++) {
+ int gpio = of_get_gpio(dev->of_node, i);
+ if (enable) {
+ rc = gpio_request(gpio, "wcnss_wlan");
+ if (rc) {
+ pr_err("WCNSS gpio_request %d err %d\n",
+ gpio, rc);
+ goto fail;
+ }
+ } else
+ gpio_free(gpio);
+ }
+
+ return rc;
+
+fail:
+ for (j = WCNSS_WLAN_NUM_GPIOS-1; j >= 0; j--) {
+ int gpio = of_get_gpio(dev->of_node, i);
+ gpio_free(gpio);
+ }
+ return rc;
}
static int
@@ -469,6 +503,15 @@
}
EXPORT_SYMBOL(wcnss_allow_suspend);
+int wcnss_hardware_type(void)
+{
+ if (penv)
+ return penv->wcnss_hw_type;
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_hardware_type);
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -551,6 +594,8 @@
{
int ret;
struct qcom_wcnss_opts *pdata;
+ int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has_pronto_hw");
/* make sure we are only triggered once */
if (penv->triggered)
@@ -559,25 +604,36 @@
/* initialize the WCNSS device configuration */
pdata = pdev->dev.platform_data;
- if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo)
- has_48mhz_xo = pdata->has_48mhz_xo;
+ if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
+ if (has_pronto_hw) {
+ has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has_48mhz_xo");
+ penv->wcnss_hw_type = WCNSS_PRONTO_HW;
+ } else {
+ penv->wcnss_hw_type = WCNSS_RIVA_HW;
+ has_48mhz_xo = pdata->has_48mhz_xo;
+ }
+ }
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
penv->thermal_mitigation = 0;
strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
- penv->gpios_5wire = platform_get_resource_byname(pdev, IORESOURCE_IO,
- "wcnss_gpios_5wire");
-
- /* allocate 5-wire GPIO resources */
- if (!penv->gpios_5wire) {
- dev_err(&pdev->dev, "insufficient IO resources\n");
- ret = -ENOENT;
- goto fail_gpio_res;
- }
-
/* Configure 5 wire GPIOs */
- ret = wcnss_gpios_config(penv->gpios_5wire, true);
+ if (!has_pronto_hw) {
+ penv->gpios_5wire = platform_get_resource_byname(pdev,
+ IORESOURCE_IO, "wcnss_gpios_5wire");
+
+ /* allocate 5-wire GPIO resources */
+ if (!penv->gpios_5wire) {
+ dev_err(&pdev->dev, "insufficient IO resources\n");
+ ret = -ENOENT;
+ goto fail_gpio_res;
+ }
+ ret = wcnss_gpios_config(penv->gpios_5wire, true);
+ } else
+ ret = wcnss_pronto_gpios_config(&pdev->dev, true);
+
if (ret) {
dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
goto fail_gpio_res;
@@ -627,7 +683,10 @@
wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
WCNSS_WLAN_SWITCH_OFF);
fail_power:
- wcnss_gpios_config(penv->gpios_5wire, false);
+ if (has_pronto_hw)
+ ret = wcnss_pronto_gpios_config(&pdev->dev, false);
+ else
+ wcnss_gpios_config(penv->gpios_5wire, false);
fail_gpio_res:
kfree(penv);
penv = NULL;
@@ -724,11 +783,21 @@
.resume = wcnss_wlan_resume,
};
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+static struct of_device_id msm_wcnss_pronto_match[] = {
+ {.compatible = "qcom,wcnss_wlan"},
+ {}
+};
+#endif
+
static struct platform_driver wcnss_wlan_driver = {
.driver = {
.name = DEVICE,
.owner = THIS_MODULE,
.pm = &wcnss_wlan_pm_ops,
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+ .of_match_table = msm_wcnss_pronto_match,
+#endif
},
.probe = wcnss_wlan_probe,
.remove = __devexit_p(wcnss_wlan_remove),
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index bf984b6..94e76d8 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -49,7 +49,7 @@
if (!gc) {
pr_debug("%s: gpio controller %s isn't registered\n",
np->full_name, gpiospec.np->full_name);
- ret = -ENODEV;
+ ret = -EPROBE_DEFER;
goto err1;
}
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index f87a06a..3512fa8 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -88,6 +88,8 @@
#define QC_DEVID_SAT2 0x4
#define QC_DEVID_PGD 0x5
#define QC_MSM_DEVS 5
+#define INIT_MX_RETRIES 10
+#define DEF_RETRY_MS 10
#define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
#define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
@@ -175,6 +177,7 @@
MGR_INT_CLR = 0x218,
MGR_TX_MSG = 0x230,
MGR_RX_MSG = 0x270,
+ MGR_IE_STAT = 0x2F0,
MGR_VE_STAT = 0x300,
};
@@ -449,8 +452,34 @@
writel_relaxed(MGR_INT_TX_MSG_SENT,
dev->base + MGR_INT_CLR);
else {
+ u32 mgr_stat = readl_relaxed(dev->base + MGR_STATUS);
+ u32 mgr_ie_stat = readl_relaxed(dev->base +
+ MGR_IE_STAT);
+ u32 frm_stat = readl_relaxed(dev->base + FRM_STAT);
+ u32 frm_cfg = readl_relaxed(dev->base + FRM_CFG);
+ u32 frm_intr_stat = readl_relaxed(dev->base +
+ FRM_INT_STAT);
+ u32 frm_ie_stat = readl_relaxed(dev->base +
+ FRM_IE_STAT);
+ u32 intf_stat = readl_relaxed(dev->base + INTF_STAT);
+ u32 intf_intr_stat = readl_relaxed(dev->base +
+ INTF_INT_STAT);
+ u32 intf_ie_stat = readl_relaxed(dev->base +
+ INTF_IE_STAT);
+
writel_relaxed(MGR_INT_TX_NACKED_2,
dev->base + MGR_INT_CLR);
+ pr_err("TX Nack MGR dump:int_stat:0x%x, mgr_stat:0x%x",
+ stat, mgr_stat);
+ pr_err("TX Nack MGR dump:ie_stat:0x%x", mgr_ie_stat);
+ pr_err("TX Nack FRM dump:int_stat:0x%x, frm_stat:0x%x",
+ frm_intr_stat, frm_stat);
+ pr_err("TX Nack FRM dump:frm_cfg:0x%x, ie_stat:0x%x",
+ frm_cfg, frm_ie_stat);
+ pr_err("TX Nack INTF dump:intr_st:0x%x, intf_stat:0x%x",
+ intf_intr_stat, intf_stat);
+ pr_err("TX Nack INTF dump:ie_stat:0x%x", intf_ie_stat);
+
dev->err = -EIO;
}
/*
@@ -863,7 +892,8 @@
dev->wr_comp = &done;
msm_send_msg_buf(ctrl, pbuf, txn->rl);
timeout = wait_for_completion_timeout(&done, HZ);
-
+ if (!timeout)
+ dev->wr_comp = NULL;
if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
@@ -903,13 +933,28 @@
return timeout ? dev->err : -ETIMEDOUT;
}
+static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
+{
+ int msec_per_frm = 0;
+ int sfr_per_sec;
+ /* Wait for 1 superframe, or default time and then retry */
+ sfr_per_sec = dev->framer.superfreq /
+ (1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
+ if (sfr_per_sec)
+ msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
+ if (msec_per_frm < DEF_RETRY_MS)
+ msec_per_frm = DEF_RETRY_MS;
+ msleep(msec_per_frm);
+}
static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
u8 elen, u8 laddr)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
- DECLARE_COMPLETION_ONSTACK(done);
- int timeout;
+ struct completion done;
+ int timeout, ret, retries = 0;
u32 *buf;
+retry_laddr:
+ init_completion(&done);
mutex_lock(&dev->tx_lock);
buf = msm_get_msg_buf(ctrl, 9);
buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
@@ -920,10 +965,27 @@
buf[2] = laddr;
dev->wr_comp = &done;
- msm_send_msg_buf(ctrl, buf, 9);
+ ret = msm_send_msg_buf(ctrl, buf, 9);
timeout = wait_for_completion_timeout(&done, HZ);
+ if (!timeout)
+ dev->err = -ETIMEDOUT;
+ if (dev->err) {
+ ret = dev->err;
+ dev->err = 0;
+ dev->wr_comp = NULL;
+ }
mutex_unlock(&dev->tx_lock);
- return timeout ? dev->err : -ETIMEDOUT;
+ if (ret) {
+ pr_err("set LADDR:0x%x failed:ret:%d, retrying", laddr, ret);
+ if (retries < INIT_MX_RETRIES) {
+ msm_slim_wait_retry(dev);
+ retries++;
+ goto retry_laddr;
+ } else {
+ pr_err("set LADDR failed after retrying:ret:%d", ret);
+ }
+ }
+ return ret;
}
static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
@@ -1154,6 +1216,8 @@
msm_sat_enqueue(sat, (u32 *)buf, len);
queue_work(sat->wq, &sat->wd);
}
+ if (ret)
+ pr_err("assign laddr failed, error:%d", ret);
} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
mc == SLIM_MSG_MC_REPLY_VALUE) {
u8 tid = buf[3];
@@ -1196,7 +1260,7 @@
bool gen_ack = false;
u8 tid;
u8 wbuf[8];
- int i;
+ int i, retries = 0;
txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
txn.dt = SLIM_MSG_DEST_LOGICALADDR;
txn.ec = 0;
@@ -1209,7 +1273,6 @@
if (mt == SLIM_MSG_MT_CORE &&
mc == SLIM_MSG_MC_REPORT_PRESENT) {
- u8 laddr;
u8 e_addr[6];
for (i = 0; i < 6; i++)
e_addr[i] = buf[7-i];
@@ -1219,8 +1282,6 @@
if (satv >= 0)
sat->pending_capability = true;
}
- slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
- sat->satcl.laddr = laddr;
/*
* Since capability message is already sent, present
* message will indicate subsystem hosting this
@@ -1232,7 +1293,7 @@
for (i = 0; i < sat->nsatch; i++) {
if (sat->satch[i].reconf) {
pr_err("SSR, sat:%d, rm ch:%d",
- laddr,
+ sat->satcl.laddr,
sat->satch[i].chan);
slim_control_ch(&sat->satcl,
sat->satch[i].chanh,
@@ -1284,8 +1345,21 @@
wbuf[3] = SAT_MSG_PROT;
txn.wbuf = wbuf;
txn.len = 4;
- sat->sent_capability = true;
- msm_xfer_msg(&dev->ctrl, &txn);
+ ret = msm_xfer_msg(&dev->ctrl, &txn);
+ if (ret) {
+ pr_err("capability for:0x%x fail:%d, retry:%d",
+ sat->satcl.laddr, ret, retries);
+ if (retries < INIT_MX_RETRIES) {
+ msm_slim_wait_retry(dev);
+ retries++;
+ goto send_capability;
+ } else {
+ pr_err("failed after all retries:%d",
+ ret);
+ }
+ } else {
+ sat->sent_capability = true;
+ }
break;
case SLIM_USR_MC_ADDR_QUERY:
memcpy(&wbuf[1], &buf[4], 6);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 8dce000..da2a30d 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -983,6 +983,15 @@
ret = -ETIMEDOUT;
} else
ret = 0;
+ } else if (ret < 0 && !msg->comp) {
+ struct slim_msg_txn *txn;
+ dev_err(&ctrl->dev, "slimbus Read error");
+ mutex_lock(&ctrl->m_ctrl);
+ txn = ctrl->txnt[tid];
+ /* Invalidate the transaction */
+ ctrl->txnt[tid] = NULL;
+ mutex_unlock(&ctrl->m_ctrl);
+ kfree(txn);
}
} else
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index b97ea1c..fd9a819 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -155,6 +155,7 @@
int calib_len;
struct resource *res_tsens_mem;
struct resource *res_calib_mem;
+ struct work_struct tsens_work;
struct tsens_tm_device_sensor sensor[0];
};
@@ -428,9 +429,10 @@
NULL, "type");
}
-static irqreturn_t tsens_isr(int irq, void *data)
+static void tsens_scheduler_fn(struct work_struct *work)
{
- struct tsens_tm_device *tm = data;
+ struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
+ tsens_work);
unsigned int i, status, threshold;
unsigned int sensor_status_addr, sensor_status_ctrl_addr;
@@ -464,6 +466,12 @@
sensor_status_ctrl_addr += TSENS_SN_ADDR_OFFSET;
}
mb();
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+ schedule_work(&tmdev->tsens_work);
+
return IRQ_HANDLED;
}
@@ -884,6 +892,8 @@
}
platform_set_drvdata(pdev, tmdev);
+ INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
+
return 0;
fail:
if (tmdev->tsens_calib_addr)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 3f4d87b..4a9c9a3 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -174,7 +174,7 @@
#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
#define UARTDM_RX_BUF_SIZE 512
#define RETRY_TIMEOUT 5
-#define UARTDM_NR 5
+#define UARTDM_NR 256
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
@@ -2025,6 +2025,8 @@
msm_serial_debugfs_init(msm_uport, pdev->id);
uport->line = pdev->id;
+ if (pdata != NULL && pdata->userid && pdata->userid <= UARTDM_NR)
+ uport->line = pdata->userid;
return uart_add_one_port(&msm_hs_driver, uport);
}
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index e0520c7..087c928 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -586,11 +586,11 @@
resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
- resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
- (params->dev->mtu
+ resp->MaxTransferSize = cpu_to_le32(
+ params->dev->mtu
+ sizeof(struct ethhdr)
+ sizeof(struct rndis_packet_msg_type)
- + 22));
+ + 22);
resp->PacketAlignmentFactor = cpu_to_le32(0);
resp->AFListOffset = cpu_to_le32(0);
resp->AFListSize = cpu_to_le32(0);
@@ -902,8 +902,7 @@
rndis_per_dev_params[i].used = 1;
rndis_per_dev_params[i].resp_avail = resp_avail;
rndis_per_dev_params[i].v = v;
- rndis_per_dev_params[i].max_pkt_per_xfer =
- TX_SKB_HOLD_THRESHOLD;
+ rndis_per_dev_params[i].max_pkt_per_xfer = 1;
pr_debug("%s: configNr = %d\n", __func__, i);
return i;
}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 86b2d45..9ef7e43 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -36,6 +36,8 @@
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
#include <mach/msm_bus.h>
#include <mach/clk.h>
@@ -50,6 +52,18 @@
#define USB_REG_END_OFFSET 0x250
static struct workqueue_struct *ehci_wq;
+struct ehci_timer {
+#define GPT_LD(p) ((p) & 0x00FFFFFF)
+ u32 gptimer0_ld;
+#define GPT_RUN BIT(31)
+#define GPT_RESET BIT(30)
+#define GPT_MODE BIT(24)
+#define GPT_CNT(p) ((p) & 0x00FFFFFF)
+ u32 gptimer0_ctrl;
+
+ u32 gptimer1_ld;
+ u32 gptimer1_ctrl;
+};
struct msm_hsic_hcd {
struct ehci_hcd ehci;
@@ -74,6 +88,13 @@
struct work_struct bus_vote_w;
bool bus_vote;
+
+ /* gp timer */
+ struct ehci_timer __iomem *timer;
+ struct completion gpt0_completion;
+ struct completion rt_completion;
+ int resume_status;
+ int resume_again;
};
struct msm_hsic_hcd *__mehci;
@@ -806,9 +827,12 @@
__func__, ret);
}
+#define STS_GPTIMER0_INTERRUPT BIT(24)
static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ u32 status;
if (atomic_read(&mehci->in_lpm)) {
disable_irq_nosync(hcd->irq);
@@ -818,14 +842,38 @@
return IRQ_HANDLED;
}
+ status = ehci_readl(ehci, &ehci->regs->status);
+
+ if (status & STS_GPTIMER0_INTERRUPT) {
+ int timeleft;
+
+ dbg_log_event(NULL, "FPR: gpt0_isr", 0);
+
+ timeleft = GPT_CNT(ehci_readl(ehci,
+ &mehci->timer->gptimer1_ctrl));
+ if (timeleft) {
+ ehci_writel(ehci, ehci_readl(ehci,
+ &ehci->regs->command) | CMD_RUN,
+ &ehci->regs->command);
+ } else
+ mehci->resume_again = 1;
+
+ dbg_log_event(NULL, "FPR: timeleft", timeleft);
+
+ complete(&mehci->gpt0_completion);
+ ehci_writel(ehci, STS_GPTIMER0_INTERRUPT, &ehci->regs->status);
+ }
+
return ehci_irq(hcd);
}
static int ehci_hsic_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
int retval;
+ mehci->timer = USB_HS_GPTIMER_BASE;
ehci->caps = USB_CAPLENGTH;
ehci->regs = USB_CAPLENGTH +
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
@@ -875,10 +923,191 @@
return ehci_bus_suspend(hcd);
}
+#define RESUME_RETRY_LIMIT 3
+#define RESUME_SIGNAL_TIME_MS (21 * 999)
+#define RESUME_SIGNAL_TIME_SOF_MS (23 * 999)
+static int msm_hsic_resume_thread(void *data)
+{
+ struct msm_hsic_hcd *mehci = data;
+ struct usb_hcd *hcd = hsic_to_hcd(mehci);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 temp;
+ unsigned long resume_needed = 0;
+ int retry_cnt = 0;
+ int tight_resume = 0;
+
+ dbg_log_event(NULL, "Resume RH", 0);
+
+ /* keep delay between bus states */
+ if (time_before(jiffies, ehci->next_statechange))
+ usleep_range(5000, 5000);
+
+ spin_lock_irq(&ehci->lock);
+ if (!HCD_HW_ACCESSIBLE(hcd)) {
+ spin_unlock_irq(&ehci->lock);
+ mehci->resume_status = -ESHUTDOWN;
+ complete(&mehci->rt_completion);
+ return 0;
+ }
+
+ if (unlikely(ehci->debug)) {
+ if (!dbgp_reset_prep())
+ ehci->debug = NULL;
+ else
+ dbgp_external_startup();
+ }
+
+ /* at least some APM implementations will try to deliver
+ * IRQs right away, so delay them until we're ready.
+ */
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+
+ /* re-init operational registers */
+ ehci_writel(ehci, 0, &ehci->regs->segment);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
+
+ /*CMD_RUN will be set after, PORT_RESUME gets cleared*/
+ if (ehci->resume_sof_bug)
+ ehci->command &= ~CMD_RUN;
+
+ /* restore CMD_RUN, framelist size, and irq threshold */
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+
+ /* manually resume the ports we suspended during bus_suspend() */
+resume_again:
+ if (retry_cnt >= RESUME_RETRY_LIMIT) {
+ pr_info("retry count(%d) reached max, resume in tight loop\n",
+ retry_cnt);
+ tight_resume = 1;
+ }
+
+
+ temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ if (test_bit(0, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) {
+ temp |= PORT_RESUME;
+ set_bit(0, &resume_needed);
+ }
+ dbg_log_event(NULL, "FPR: Set", temp);
+ ehci_writel(ehci, temp, &ehci->regs->port_status[0]);
+
+ /* HSIC controller has a h/w bug due to which it can try to send SOFs
+ * (start of frames) during port resume resulting in phy lockup. HSIC hw
+ * controller in MSM clears FPR bit after driving the resume signal for
+ * 20ms. Workaround is to stop SOFs before driving resume and then start
+ * sending SOFs immediately. Need to send SOFs within 3ms of resume
+ * completion otherwise peripheral may enter undefined state. As
+ * usleep_range does not gurantee exact sleep time, GPTimer is used to
+ * to time the resume sequence. If driver exceeds allowable time SOFs,
+ * repeat the resume process.
+ */
+ if (ehci->resume_sof_bug && resume_needed) {
+ if (!tight_resume) {
+ mehci->resume_again = 0;
+ ehci_writel(ehci, GPT_LD(RESUME_SIGNAL_TIME_MS),
+ &mehci->timer->gptimer0_ld);
+ ehci_writel(ehci, GPT_RESET | GPT_RUN,
+ &mehci->timer->gptimer0_ctrl);
+ ehci_writel(ehci, INTR_MASK | STS_GPTIMER0_INTERRUPT,
+ &ehci->regs->intr_enable);
+
+ ehci_writel(ehci, GPT_LD(RESUME_SIGNAL_TIME_SOF_MS),
+ &mehci->timer->gptimer1_ld);
+ ehci_writel(ehci, GPT_RESET | GPT_RUN,
+ &mehci->timer->gptimer1_ctrl);
+
+ spin_unlock_irq(&ehci->lock);
+ wait_for_completion(&mehci->gpt0_completion);
+ spin_lock_irq(&ehci->lock);
+ } else {
+ dbg_log_event(NULL, "FPR: Tightloop", 0);
+ /* do the resume in a tight loop */
+ handshake(ehci, &ehci->regs->port_status[0],
+ PORT_RESUME, 0, 22 * 1000);
+ ehci_writel(ehci, ehci_readl(ehci,
+ &ehci->regs->command) | CMD_RUN,
+ &ehci->regs->command);
+ }
+
+ if (mehci->resume_again) {
+ int temp;
+
+ dbg_log_event(NULL, "FPR: Re-Resume", retry_cnt);
+ pr_info("FPR: retry count: %d\n", retry_cnt);
+ spin_unlock_irq(&ehci->lock);
+ temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ temp &= ~PORT_RWC_BITS;
+ temp |= PORT_SUSPEND;
+ ehci_writel(ehci, temp, &ehci->regs->port_status[0]);
+ /* Keep the bus idle for 5ms so that peripheral
+ * can detect and initiate suspend
+ */
+ usleep_range(5000, 5000);
+ dbg_log_event(NULL,
+ "FPR: RResume",
+ ehci_readl(ehci, &ehci->regs->port_status[0]));
+ spin_lock_irq(&ehci->lock);
+ mehci->resume_again = 0;
+ retry_cnt++;
+ goto resume_again;
+ }
+ }
+
+ dbg_log_event(NULL, "FPR: RT-Done", 0);
+ mehci->resume_status = 1;
+ spin_unlock_irq(&ehci->lock);
+
+ complete(&mehci->rt_completion);
+
+ return 0;
+}
+
static int ehci_hsic_bus_resume(struct usb_hcd *hcd)
{
- dbg_log_event(NULL, "Resume RH", 0);
- return ehci_bus_resume(hcd);
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 temp;
+ struct task_struct *resume_thread = NULL;
+
+ mehci->resume_status = 0;
+ resume_thread = kthread_run(msm_hsic_resume_thread,
+ mehci, "hsic_resume_thread");
+ if (IS_ERR(resume_thread)) {
+ pr_err("Error creating resume thread:%lu\n",
+ PTR_ERR(resume_thread));
+ return PTR_ERR(resume_thread);
+ }
+
+ wait_for_completion(&mehci->rt_completion);
+
+ if (mehci->resume_status < 0)
+ return mehci->resume_status;
+
+ dbg_log_event(NULL, "FPR: Wokeup", 0);
+ spin_lock_irq(&ehci->lock);
+ (void) ehci_readl(ehci, &ehci->regs->command);
+
+ temp = 0;
+ if (ehci->async->qh_next.qh)
+ temp |= CMD_ASE;
+ if (ehci->periodic_sched)
+ temp |= CMD_PSE;
+ if (temp) {
+ ehci->command |= temp;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ }
+
+ ehci->next_statechange = jiffies + msecs_to_jiffies(5);
+ hcd->state = HC_STATE_RUNNING;
+ ehci->rh_state = EHCI_RH_RUNNING;
+
+ /* Now we can safely re-enable irqs */
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
+
+ spin_unlock_irq(&ehci->lock);
+
+ return 0;
}
static struct hc_driver msm_hsic_driver = {
@@ -1328,6 +1557,8 @@
goto deinit_clocks;
}
+ init_completion(&mehci->rt_completion);
+ init_completion(&mehci->gpt0_completion);
ret = msm_hsic_reset(mehci);
if (ret) {
dev_err(&pdev->dev, "unable to initialize PHY\n");
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index ba7658b..cad411d 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/ratelimit.h>
#include <linux/uaccess.h>
@@ -38,6 +39,7 @@
__u8 out_epAddr;
int err;
struct kref kref;
+ struct mutex ifc_mutex;
struct diag_bridge_ops *ops;
struct platform_device *pdev;
@@ -120,24 +122,34 @@
pr_debug("reading %d bytes", size);
- if (!dev || !dev->ifc) {
+ if (!dev) {
pr_err("device is disconnected");
return -ENODEV;
}
+ mutex_lock(&dev->ifc_mutex);
+ if (!dev->ifc) {
+ ret = -ENODEV;
+ goto error;
+ }
+
if (!dev->ops) {
pr_err("bridge is not open");
- return -ENODEV;
+ ret = -ENODEV;
+ goto error;
}
if (!size) {
dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
/* if there was a previous unrecoverable error, just quit */
- if (dev->err)
- return -ENODEV;
+ if (dev->err) {
+ ret = -ENODEV;
+ goto error;
+ }
kref_get(&dev->kref);
@@ -145,7 +157,7 @@
if (!urb) {
dev_err(&dev->ifc->dev, "unable to allocate urb\n");
ret = -ENOMEM;
- goto error;
+ goto put_error;
}
ret = usb_autopm_get_interface(dev->ifc);
@@ -170,9 +182,11 @@
free_error:
usb_free_urb(urb);
-error:
+put_error:
if (ret) /* otherwise this is done in the completion handler */
kref_put(&dev->kref, diag_bridge_delete);
+error:
+ mutex_unlock(&dev->ifc_mutex);
return ret;
}
EXPORT_SYMBOL(diag_bridge_read);
@@ -210,24 +224,34 @@
pr_debug("writing %d bytes", size);
- if (!dev || !dev->ifc) {
+ if (!dev) {
pr_err("device is disconnected");
return -ENODEV;
}
+ mutex_lock(&dev->ifc_mutex);
+ if (!dev->ifc) {
+ ret = -ENODEV;
+ goto error;
+ }
+
if (!dev->ops) {
pr_err("bridge is not open");
- return -ENODEV;
+ ret = -ENODEV;
+ goto error;
}
if (!size) {
dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
/* if there was a previous unrecoverable error, just quit */
- if (dev->err)
- return -ENODEV;
+ if (dev->err) {
+ ret = -ENODEV;
+ goto error;
+ }
kref_get(&dev->kref);
@@ -235,7 +259,7 @@
if (!urb) {
dev_err(&dev->ifc->dev, "unable to allocate urb\n");
ret = -ENOMEM;
- goto error;
+ goto put_error;
}
ret = usb_autopm_get_interface(dev->ifc);
@@ -262,9 +286,11 @@
free_error:
usb_free_urb(urb);
-error:
+put_error:
if (ret) /* otherwise this is done in the completion handler */
kref_put(&dev->kref, diag_bridge_delete);
+error:
+ mutex_unlock(&dev->ifc_mutex);
return ret;
}
EXPORT_SYMBOL(diag_bridge_write);
@@ -381,6 +407,7 @@
dev->udev = usb_get_dev(interface_to_usbdev(ifc));
dev->ifc = ifc;
kref_init(&dev->kref);
+ mutex_init(&dev->ifc_mutex);
init_usb_anchor(&dev->submitted);
ifc_desc = ifc->cur_altsetting;
@@ -422,7 +449,9 @@
dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
platform_device_unregister(dev->pdev);
+ mutex_lock(&dev->ifc_mutex);
dev->ifc = NULL;
+ mutex_unlock(&dev->ifc_mutex);
diag_bridge_debugfs_cleanup();
kref_put(&dev->kref, diag_bridge_delete);
usb_set_intfdata(ifc, NULL);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 59ae13b..c78fd0c 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -990,10 +990,10 @@
}
ch_id--;
- ctrl_bridge_disconnect(ch_id);
+ ctrl_bridge_disconnect(dev->id);
platform_device_unregister(dev->pdev);
usb_set_intfdata(intf, NULL);
- __dev[ch_id] = NULL;
+ __dev[dev->id] = NULL;
cancel_work_sync(&dev->process_rx_w);
cancel_work_sync(&dev->kevent);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 70685e7..4fc78cd 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1537,6 +1537,7 @@
mdp_clk_disable_unprepare();
}
}
+ pr_debug("%s: on=%d cnt=%d\n", __func__, on, mdp_clk_cnt);
mutex_unlock(&mdp_suspend_mutex);
}
@@ -2060,8 +2061,10 @@
int ret = 0;
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+ pr_debug("%s:+\n", __func__);
mdp_histogram_ctrl_all(FALSE);
+ mdp_clk_ctrl(1);
if (mfd->panel.type == MIPI_CMD_PANEL)
mdp4_dsi_cmd_off(pdev);
else if (mfd->panel.type == MIPI_VIDEO_PANEL)
@@ -2074,9 +2077,11 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_off(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_clk_ctrl(0);
if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
mdp_dsi_cmd_overlay_suspend(mfd);
+ pr_debug("%s:-\n", __func__);
return ret;
}
@@ -2097,6 +2102,8 @@
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
+ pr_debug("%s:+\n", __func__);
+
if (mdp_rev >= MDP_REV_40) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_clk_ctrl(1);
@@ -2126,8 +2133,8 @@
ret = panel_next_on(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
mdp_histogram_ctrl_all(TRUE);
+ pr_debug("%s:-\n", __func__);
return ret;
}
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 054741f..c845053 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -480,7 +480,7 @@
struct mdp4_overlay_pipe *pipe);
void mdp4_dmae_done_dtv(void);
void mdp4_dtv_wait4vsync(int cndx, long long *vtime);
-void mdp4_dtv_vsync_ctrl(int cndx, int enable);
+void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable);
void mdp4_dtv_base_swap(int cndx, struct mdp4_overlay_pipe *pipe);
#else
static inline void mdp4_overlay_dtv_start(void)
@@ -516,7 +516,7 @@
{
/* empty */
}
-static inline void mdp4_dtv_vsync_ctrl(int cndx, long long *vtime)
+static inline void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable)
{
/* empty */
}
@@ -548,7 +548,7 @@
int mdp4_atv_off(struct platform_device *pdev);
void mdp4_dsi_video_fxn_register(cmd_fxn_t fxn);
void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd);
-void mdp4_lcdc_vsync_ctrl(int cndx, int enable);
+void mdp4_lcdc_vsync_ctrl(struct fb_info *info, int enable);
void mdp4_overlay0_done_dsi_video(int cndx);
void mdp4_overlay0_done_dsi_cmd(int cndx);
void mdp4_primary_rdptr(void);
@@ -773,8 +773,8 @@
void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime);
void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
-void mdp4_dsi_cmd_vsync_ctrl(int cndx, int enable);
-void mdp4_dsi_video_vsync_ctrl(int cndx, int enable);
+void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable);
+void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable);
#ifdef CONFIG_FB_MSM_MDP303
static inline void mdp4_dsi_cmd_del_timer(void)
{
@@ -822,10 +822,12 @@
struct mdp4_overlay_pipe *pipe)
{
}
-static inline void mdp4_dsi_cmd_vsync_ctrl(int cndx, int enable)
+static inline void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info,
+ int enable)
{
}
-static inline void mdp4_dsi_video_vsync_ctrl(int cndx, int enable)
+static inline void mdp4_dsi_video_vsync_ctrl(struct fb_info *info,
+ int enable)
{
}
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index c07b3a7..03b4f43 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2463,6 +2463,11 @@
mfd->panel_info.type == MIPI_CMD_PANEL) ?
mfd->panel_info.mipi.dsi_pclk_rate :
mfd->panel_info.clk_rate;
+
+ if (mfd->panel_info.type == LVDS_PANEL &&
+ mfd->panel_info.lvds.channel_mode == LVDS_DUAL_CHANNEL_MODE)
+ pclk = pclk << 1;
+
if (!pclk) {
pipe->req_clk = mdp_max_clk;
pr_err("%s panel pixel clk is zero!\n", __func__);
@@ -2569,7 +2574,8 @@
* required(FIR).
*/
if ((mfd->panel_info.lcdc.v_back_porch <= 4) &&
- (pipe->src_h != pipe->dst_h)) {
+ (pipe->src_h != pipe->dst_h) &&
+ (mfd->panel_info.lcdc.v_back_porch)) {
u32 clk = 0;
clk = 4 * (pclk >> shift) / mfd->panel_info.lcdc.v_back_porch;
clk <<= shift;
@@ -3174,13 +3180,13 @@
if (!hdmi_prim_display && info->node == 0) {
if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
- mdp4_dsi_video_vsync_ctrl(0, cmd);
+ mdp4_dsi_video_vsync_ctrl(info, cmd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
- mdp4_dsi_cmd_vsync_ctrl(0, cmd);
+ mdp4_dsi_cmd_vsync_ctrl(info, cmd);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
- mdp4_lcdc_vsync_ctrl(0, cmd);
+ mdp4_lcdc_vsync_ctrl(info, cmd);
} else if (hdmi_prim_display || info->node == 1)
- mdp4_dtv_vsync_ctrl(0, cmd);
+ mdp4_dtv_vsync_ctrl(info, cmd);
return 0;
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index c788c33..6232de0 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -39,7 +39,7 @@
static int vsync_start_y_adjust = 4;
#define MAX_CONTROLLER 1
-#define VSYNC_EXPIRE_TICK 4
+#define VSYNC_EXPIRE_TICK 8
static struct vsycn_ctrl {
struct device *dev;
@@ -58,7 +58,7 @@
int blt_change;
int blt_free;
int blt_end;
- int fake_vsync;
+ int uevent;
struct mutex update_lock;
struct completion ov_comp;
struct completion dmap_comp;
@@ -70,6 +70,7 @@
int vsync_enabled;
int clk_enabled;
int clk_control;
+ int new_update;
ktime_t vsync_time;
struct work_struct vsync_work;
struct work_struct clk_work;
@@ -379,26 +380,59 @@
return cnt;
}
-void mdp4_dsi_cmd_vsync_ctrl(int cndx, int enable)
-{
- struct vsycn_ctrl *vctrl;
+static void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd);
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
+void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct vsycn_ctrl *vctrl;
+ unsigned long flags;
+ int clk_set_on = 0;
+ int cndx = 0;
vctrl = &vsync_ctrl_db[cndx];
- if (enable && vctrl->fake_vsync) {
- vctrl->fake_vsync = 0;
- schedule_work(&vctrl->vsync_work);
+ pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->vsync_enabled, enable);
+
+ mutex_lock(&vctrl->update_lock);
+
+ if (vctrl->vsync_enabled == enable) {
+ mutex_unlock(&vctrl->update_lock);
+ return;
}
- if (vctrl->vsync_enabled == enable)
- return;
-
vctrl->vsync_enabled = enable;
+
+ if (enable) {
+ if (vctrl->clk_enabled == 0) {
+ pr_debug("%s: SET_CLK_ON\n", __func__);
+ mipi_dsi_clk_cfg(1);
+ mdp_clk_ctrl(1);
+ vctrl->clk_enabled = 1;
+ clk_set_on = 1;
+ }
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ vctrl->uevent = 1;
+ vctrl->new_update = 1;
+ if (clk_set_on) {
+ vsync_irq_enable(INTR_PRIMARY_RDPTR,
+ MDP_PRIM_RDPTR_TERM);
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ mdp4_overlay_update_dsi_cmd(mfd);
+ } else {
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 1;
+ vctrl->uevent = 0;
+ if (vctrl->clk_enabled)
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ }
+ mutex_unlock(&vctrl->update_lock);
}
void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -479,13 +513,21 @@
pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id());
vctrl->rdptr_intr_tot++;
vctrl->vsync_time = ktime_get();
- schedule_work(&vctrl->vsync_work);
spin_lock(&vctrl->spin_lock);
+ if (vctrl->uevent)
+ schedule_work(&vctrl->vsync_work);
+
if (vctrl->wait_vsync_cnt) {
complete(&vctrl->vsync_comp);
vctrl->wait_vsync_cnt = 0;
}
+
+ if (vctrl->expire_tick) {
+ vctrl->expire_tick--;
+ if (vctrl->expire_tick == 0)
+ schedule_work(&vctrl->clk_work);
+ }
spin_unlock(&vctrl->spin_lock);
}
@@ -578,16 +620,19 @@
{
struct vsycn_ctrl *vctrl =
container_of(work, typeof(*vctrl), clk_work);
+ unsigned long flags;
mutex_lock(&vctrl->update_lock);
- if (vctrl->clk_control) {
- if (vctrl->clk_enabled) {
- mdp_clk_ctrl(0);
- vctrl->clk_enabled = 0;
- vctrl->fake_vsync = 1;
- }
+ if (vctrl->clk_control && vctrl->clk_enabled) {
+ pr_debug("%s: SET_CLK_OFF\n", __func__);
+ mdp_clk_ctrl(0);
+ mipi_dsi_clk_cfg(0);
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+ vctrl->clk_enabled = 0;
+ vctrl->clk_control = 0;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
}
-
mutex_unlock(&vctrl->update_lock);
}
@@ -746,7 +791,7 @@
pipe->srcp0_addr = (uint32)src;
}
-void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
+static void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
{
int ptype;
struct mdp4_overlay_pipe *pipe;
@@ -760,30 +805,31 @@
vctrl = &vsync_ctrl_db[cndx];
- /* MDP cmd block enable */
- mdp_clk_ctrl(1);
+ if (vctrl->base_pipe == NULL) {
+ ptype = mdp4_overlay_format2type(mfd->fb_imgType);
+ if (ptype < 0)
+ printk(KERN_INFO "%s: format2type failed\n", __func__);
+ pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
+ if (pipe == NULL) {
+ printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
+ return;
+ }
+ pipe->pipe_used++;
+ pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
+ pipe->mixer_num = MDP4_MIXER0;
+ pipe->src_format = mfd->fb_imgType;
+ mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_CMD);
+ ret = mdp4_overlay_format2pipe(pipe);
+ if (ret < 0)
+ printk(KERN_INFO "%s: format2type failed\n", __func__);
- ptype = mdp4_overlay_format2type(mfd->fb_imgType);
- if (ptype < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
- if (pipe == NULL) {
- printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
- return;
+ vctrl->base_pipe = pipe; /* keep it */
+ mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
+ pipe->ov_blt_addr = 0;
+ pipe->dma_blt_addr = 0;
+ } else {
+ pipe = vctrl->base_pipe;
}
- pipe->pipe_used++;
- pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
- pipe->mixer_num = MDP4_MIXER0;
- pipe->src_format = mfd->fb_imgType;
- mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_CMD);
- ret = mdp4_overlay_format2pipe(pipe);
- if (ret < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
-
- vctrl->base_pipe = pipe; /* keep it */
- mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
- pipe->ov_blt_addr = 0;
- pipe->dma_blt_addr = 0;
MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
@@ -795,7 +841,6 @@
/* disable dsi trigger */
MDP_OUTP(MDP_BASE + 0x000a4, 0x00);
-
mdp4_overlay_setup_pipe_addr(mfd, pipe);
mdp4_overlay_rgb_setup(pipe);
@@ -810,9 +855,7 @@
mdp4_overlay_dmap_cfg(mfd, 0);
- mdp4_mixer_stage_commit(pipe->mixer_num);
- /* MDP cmd block disable */
- mdp_clk_ctrl(0);
+ wmb();
}
/* 3D side by side */
@@ -916,7 +959,7 @@
struct msm_fb_data_type *mfd;
struct vsycn_ctrl *vctrl;
- pr_info("%s+:\n", __func__);
+ pr_debug("%s+:\n", __func__);
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
@@ -925,15 +968,13 @@
vctrl->dev = mfd->fbi->dev;
mdp_clk_ctrl(1);
- vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
-
- if (vctrl->base_pipe == NULL)
- mdp4_overlay_update_dsi_cmd(mfd);
+ mdp4_overlay_update_dsi_cmd(mfd);
+ mdp_clk_ctrl(0);
mdp4_iommu_attach();
atomic_set(&vctrl->suspend, 0);
- pr_info("%s-:\n", __func__);
+ pr_debug("%s-:\n", __func__);
return ret;
@@ -947,7 +988,7 @@
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
- pr_info("%s+:\n", __func__);
+ pr_debug("%s+:\n", __func__);
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
@@ -966,11 +1007,25 @@
mdp4_overlay_pipe_free(pipe);
vctrl->base_pipe = NULL;
- vctrl->fake_vsync = 1;
+ if (vctrl->clk_enabled) {
+ /*
+ * in case of suspend, vsycn_ctrl off is not
+ * received from frame work which left clock on
+ * then, clock need to be turned off here
+ */
+ mdp_clk_ctrl(0);
+ }
+
+ vctrl->clk_enabled = 0;
+ vctrl->vsync_enabled = 0;
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ vctrl->uevent = 0;
vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
- pr_info("%s-:\n", __func__);
+
+ pr_debug("%s-:\n", __func__);
/*
* footswitch off
@@ -1012,6 +1067,7 @@
int cndx = 0;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ unsigned long flags;
long long xx;
vctrl = &vsync_ctrl_db[cndx];
@@ -1019,13 +1075,31 @@
if (!mfd->panel_power_on)
return;
- vctrl->clk_control = 0;
pipe = vctrl->base_pipe;
if (pipe == NULL) {
pr_err("%s: NO base pipe\n", __func__);
return;
}
+ mutex_lock(&vctrl->update_lock);
+ if (!vctrl->clk_enabled) {
+ pr_err("%s: mdp clocks disabled\n", __func__);
+ mutex_unlock(&vctrl->update_lock);
+ return;
+
+ }
+ mutex_unlock(&vctrl->update_lock);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->expire_tick) {
+ /*
+ * in the middle of shutting clocks down
+ * delay to allow pan display to go through
+ */
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
mdp4_mipi_vsync_enable(mfd, pipe, 0);
mdp4_overlay_setup_pipe_addr(mfd, pipe);
@@ -1033,13 +1107,12 @@
}
mdp4_overlay_mdp_perf_upd(mfd, 1);
+
mutex_lock(&mfd->dma->ov_mutex);
mdp4_dsi_cmd_pipe_commit();
mutex_unlock(&mfd->dma->ov_mutex);
mdp4_dsi_cmd_wait4vsync(0, &xx);
- vctrl->expire_tick = VSYNC_EXPIRE_TICK;
- vctrl->clk_control = 1;
mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index a461c3b..04da0a3 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -256,14 +256,10 @@
return cnt;
}
-void mdp4_dsi_video_vsync_ctrl(int cndx, int enable)
+void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable)
{
struct vsycn_ctrl *vctrl;
-
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
+ int cndx = 0;
vctrl = &vsync_ctrl_db[cndx];
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index e131369..8a0b092 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -238,14 +238,10 @@
return cnt;
}
-void mdp4_dtv_vsync_ctrl(int cndx, int enable)
+void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable)
{
struct vsycn_ctrl *vctrl;
-
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
+ int cndx = 0;
vctrl = &vsync_ctrl_db[cndx];
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a2fabca..aa2de32 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -260,14 +260,10 @@
return cnt;
}
-void mdp4_lcdc_vsync_ctrl(int cndx, int enable)
+void mdp4_lcdc_vsync_ctrl(struct fb_info *info, int enable)
{
struct vsycn_ctrl *vctrl;
-
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
+ int cndx = 0;
vctrl = &vsync_ctrl_db[cndx];
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index df57ee1..4b76e72 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -519,6 +519,8 @@
return;
spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (!enable)
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
vsync_cntrl.vsync_irq_enabled = enable;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
@@ -532,7 +534,6 @@
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else {
- INIT_COMPLETION(vsync_cntrl.vsync_wait);
wait_for_completion(&vsync_cntrl.vsync_wait);
mdp_disable_irq(MDP_VSYNC_TERM);
}
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 09ae82f..a1f2b65 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -254,6 +254,8 @@
return;
spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (!enable)
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
vsync_cntrl.vsync_irq_enabled = enable;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
@@ -266,7 +268,6 @@
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else {
- INIT_COMPLETION(vsync_cntrl.vsync_wait);
wait_for_completion(&vsync_cntrl.vsync_wait);
mdp_disable_irq(MDP_VSYNC_TERM);
}
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index e1b78c2..10d60ab 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -335,6 +335,8 @@
return;
spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (!enable)
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
vsync_cntrl.vsync_irq_enabled = enable;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
@@ -347,7 +349,6 @@
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else {
- INIT_COMPLETION(vsync_cntrl.vsync_wait);
wait_for_completion(&vsync_cntrl.vsync_wait);
mdp_disable_irq(MDP_VSYNC_TERM);
}
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 6bc21bc..ddb6dd9 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -16,4 +16,5 @@
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_edid.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 5ea52e7..7765e6c 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -144,9 +144,9 @@
return ret;
}
-static DEVICE_ATTR(mdss_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
static struct attribute *mdss_fb_attrs[] = {
- &dev_attr_mdss_fb_type.attr,
+ &dev_attr_msm_fb_type.attr,
NULL,
};
@@ -217,6 +217,14 @@
if (rc)
return rc;
+ /*
+ * todo: Currently mfd keeps a full copy of panel data rather than
+ * pointer to it.
+ * Following line shares the fbi with panel drivers for their
+ * sysfs or any external communications with the panel driver.
+ */
+ pdata->panel_info.fbi = fbi;
+
rc = pm_runtime_set_active(mfd->fbi->dev);
if (rc < 0)
pr_err("pm_runtime: fail to set active.\n");
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
new file mode 100644
index 0000000..f720a2f
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -0,0 +1,1420 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <mach/board.h>
+#include "mdss_hdmi_edid.h"
+
+#define DBC_START_OFFSET 4
+#define HDMI_VSDB_3D_DATA_OFFSET(vsd) \
+ (!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
+
+struct hdmi_edid_sink_data {
+ u32 disp_mode_list[HDMI_VFRMT_MAX];
+ u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
+ u32 disp_multi_3d_mode_list[16];
+ u32 disp_multi_3d_mode_list_cnt;
+ u32 num_of_elements;
+ u32 preferred_video_format;
+};
+
+struct hdmi_edid_ctrl {
+ u8 pt_scan_info;
+ u8 it_scan_info;
+ u8 ce_scan_info;
+ u16 physical_address;
+ u32 video_resolution; /* selected by user */
+ u32 sink_mode; /* HDMI or DVI */
+ u8 speaker_allocation_block;
+ u8 audio_data_block_cnt;
+ u16 audio_latency;
+ u16 video_latency;
+ u32 present_3d;
+
+ struct hdmi_edid_sink_data sink_data;
+ struct hdmi_edid_init_data init_data;
+};
+
+/* The Logic ID for HDMI TX Core. Currently only support 1 HDMI TX Core. */
+struct hdmi_edid_video_mode_property_type {
+ u32 video_code;
+ u32 active_h;
+ u32 active_v;
+ u32 interlaced;
+ u32 total_h;
+ u32 total_blank_h;
+ u32 total_v;
+ u32 total_blank_v;
+ /* Must divide by 1000 to get the frequency */
+ u32 freq_h;
+ /* Must divide by 1000 to get the frequency */
+ u32 freq_v;
+ /* Must divide by 1000 to get the frequency */
+ u32 pixel_freq;
+ /* Must divide by 1000 to get the frequency */
+ u32 refresh_rate;
+ u32 aspect_ratio_4_3;
+};
+
+/* LUT is sorted from lowest Active H to highest Active H - ease searching */
+static struct hdmi_edid_video_mode_property_type
+ hdmi_edid_disp_mode_lut[] = {
+
+ /* All 640 H Active */
+ {HDMI_VFRMT_640x480p60_4_3, 640, 480, false, 800, 160, 525, 45,
+ 31465, 59940, 25175, 59940, true},
+ {HDMI_VFRMT_640x480p60_4_3, 640, 480, false, 800, 160, 525, 45,
+ 31500, 60000, 25200, 60000, true},
+
+ /* All 720 H Active */
+ {HDMI_VFRMT_720x576p50_4_3, 720, 576, false, 864, 144, 625, 49,
+ 31250, 50000, 27000, 50000, true},
+ {HDMI_VFRMT_720x480p60_4_3, 720, 480, false, 858, 138, 525, 45,
+ 31465, 59940, 27000, 59940, true},
+ {HDMI_VFRMT_720x480p60_4_3, 720, 480, false, 858, 138, 525, 45,
+ 31500, 60000, 27030, 60000, true},
+ {HDMI_VFRMT_720x576p100_4_3, 720, 576, false, 864, 144, 625, 49,
+ 62500, 100000, 54000, 100000, true},
+ {HDMI_VFRMT_720x480p120_4_3, 720, 480, false, 858, 138, 525, 45,
+ 62937, 119880, 54000, 119880, true},
+ {HDMI_VFRMT_720x480p120_4_3, 720, 480, false, 858, 138, 525, 45,
+ 63000, 120000, 54054, 120000, true},
+ {HDMI_VFRMT_720x576p200_4_3, 720, 576, false, 864, 144, 625, 49,
+ 125000, 200000, 108000, 200000, true},
+ {HDMI_VFRMT_720x480p240_4_3, 720, 480, false, 858, 138, 525, 45,
+ 125874, 239760, 108000, 239000, true},
+ {HDMI_VFRMT_720x480p240_4_3, 720, 480, false, 858, 138, 525, 45,
+ 126000, 240000, 108108, 240000, true},
+
+ /* All 1280 H Active */
+ {HDMI_VFRMT_1280x720p50_16_9, 1280, 720, false, 1980, 700, 750, 30,
+ 37500, 50000, 74250, 50000, false},
+ {HDMI_VFRMT_1280x720p60_16_9, 1280, 720, false, 1650, 370, 750, 30,
+ 44955, 59940, 74176, 59940, false},
+ {HDMI_VFRMT_1280x720p60_16_9, 1280, 720, false, 1650, 370, 750, 30,
+ 45000, 60000, 74250, 60000, false},
+ {HDMI_VFRMT_1280x720p100_16_9, 1280, 720, false, 1980, 700, 750, 30,
+ 75000, 100000, 148500, 100000, false},
+ {HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
+ 89909, 119880, 148352, 119880, false},
+ {HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
+ 90000, 120000, 148500, 120000, false},
+
+ /* All 1440 H Active */
+ {HDMI_VFRMT_1440x576i50_4_3, 1440, 576, true, 1728, 288, 625, 24,
+ 15625, 50000, 27000, 50000, true},
+ {HDMI_VFRMT_720x288p50_4_3, 1440, 288, false, 1728, 288, 312, 24,
+ 15625, 50080, 27000, 50000, true},
+ {HDMI_VFRMT_720x288p50_4_3, 1440, 288, false, 1728, 288, 313, 25,
+ 15625, 49920, 27000, 50000, true},
+ {HDMI_VFRMT_720x288p50_4_3, 1440, 288, false, 1728, 288, 314, 26,
+ 15625, 49761, 27000, 50000, true},
+ {HDMI_VFRMT_1440x576p50_4_3, 1440, 576, false, 1728, 288, 625, 49,
+ 31250, 50000, 54000, 50000, true},
+ {HDMI_VFRMT_1440x480i60_4_3, 1440, 480, true, 1716, 276, 525, 22,
+ 15734, 59940, 27000, 59940, true},
+ {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 262, 22,
+ 15734, 60054, 27000, 59940, true},
+ {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 263, 23,
+ 15734, 59826, 27000, 59940, true},
+ {HDMI_VFRMT_1440x480p60_4_3, 1440, 480, false, 1716, 276, 525, 45,
+ 31469, 59940, 54000, 59940, true},
+ {HDMI_VFRMT_1440x480i60_4_3, 1440, 480, true, 1716, 276, 525, 22,
+ 15750, 60000, 27027, 60000, true},
+ {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 262, 22,
+ 15750, 60115, 27027, 60000, true},
+ {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 263, 23,
+ 15750, 59886, 27027, 60000, true},
+ {HDMI_VFRMT_1440x480p60_4_3, 1440, 480, false, 1716, 276, 525, 45,
+ 31500, 60000, 54054, 60000, true},
+ {HDMI_VFRMT_1440x576i100_4_3, 1440, 576, true, 1728, 288, 625, 24,
+ 31250, 100000, 54000, 100000, true},
+ {HDMI_VFRMT_1440x480i120_4_3, 1440, 480, true, 1716, 276, 525, 22,
+ 31469, 119880, 54000, 119880, true},
+ {HDMI_VFRMT_1440x480i120_4_3, 1440, 480, true, 1716, 276, 525, 22,
+ 31500, 120000, 54054, 120000, true},
+ {HDMI_VFRMT_1440x576i200_4_3, 1440, 576, true, 1728, 288, 625, 24,
+ 62500, 200000, 108000, 200000, true},
+ {HDMI_VFRMT_1440x480i240_4_3, 1440, 480, true, 1716, 276, 525, 22,
+ 62937, 239760, 108000, 239000, true},
+ {HDMI_VFRMT_1440x480i240_4_3, 1440, 480, true, 1716, 276, 525, 22,
+ 63000, 240000, 108108, 240000, true},
+
+ /* All 1920 H Active */
+ {HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, false, 2200, 280, 1125,
+ 45, 67433, 59940, 148352, 59940, false},
+ {HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, true, 2200, 280, 1125,
+ 45, 67500, 60000, 148500, 60000, false},
+ {HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, false, 2640, 720, 1125,
+ 45, 56250, 50000, 148500, 50000, false},
+ {HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, false, 2750, 830, 1125,
+ 45, 26973, 23976, 74176, 24000, false},
+ {HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, false, 2750, 830, 1125,
+ 45, 27000, 24000, 74250, 24000, false},
+ {HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, false, 2640, 720, 1125,
+ 45, 28125, 25000, 74250, 25000, false},
+ {HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, false, 2200, 280, 1125,
+ 45, 33716, 29970, 74176, 30000, false},
+ {HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, false, 2200, 280, 1125,
+ 45, 33750, 30000, 74250, 30000, false},
+ {HDMI_VFRMT_1920x1080i50_16_9, 1920, 1080, true, 2304, 384, 1250,
+ 85, 31250, 50000, 72000, 50000, false},
+ {HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, true, 2200, 280, 1125,
+ 22, 33716, 59940, 74176, 59940, false},
+ {HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, true, 2200, 280, 1125,
+ 22, 33750, 60000, 74250, 60000, false},
+ {HDMI_VFRMT_1920x1080i100_16_9, 1920, 1080, true, 2640, 720, 1125,
+ 22, 56250, 100000, 148500, 100000, false},
+ {HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true, 2200, 280, 1125,
+ 22, 67432, 119880, 148352, 119980, false},
+ {HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true, 2200, 280, 1125,
+ 22, 67500, 120000, 148500, 120000, false},
+
+ /* All 2880 H Active */
+ {HDMI_VFRMT_2880x576i50_4_3, 2880, 576, true, 3456, 576, 625, 24,
+ 15625, 50000, 54000, 50000, true},
+ {HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 312, 24,
+ 15625, 50080, 54000, 50000, true},
+ {HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 313, 25,
+ 15625, 49920, 54000, 50000, true},
+ {HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 314, 26,
+ 15625, 49761, 54000, 50000, true},
+ {HDMI_VFRMT_2880x576p50_4_3, 2880, 576, false, 3456, 576, 625, 49,
+ 31250, 50000, 108000, 50000, true},
+ {HDMI_VFRMT_2880x480i60_4_3, 2880, 480, true, 3432, 552, 525, 22,
+ 15734, 59940, 54000, 59940, true},
+ {HDMI_VFRMT_2880x240p60_4_3, 2880, 480, false, 3432, 552, 262, 22,
+ 15734, 60054, 54000, 59940, true},
+ {HDMI_VFRMT_2880x240p60_4_3, 2880, 480, false, 3432, 552, 263, 23,
+ 15734, 59940, 54000, 59940, true},
+ {HDMI_VFRMT_2880x480p60_4_3, 2880, 480, false, 3432, 552, 525, 45,
+ 31469, 59940, 108000, 59940, true},
+ {HDMI_VFRMT_2880x480i60_4_3, 2880, 480, true, 3432, 552, 525, 22,
+ 15750, 60000, 54054, 60000, true},
+ {HDMI_VFRMT_2880x240p60_4_3, 2880, 240, false, 3432, 552, 262, 22,
+ 15750, 60115, 54054, 60000, true},
+ {HDMI_VFRMT_2880x240p60_4_3, 2880, 240, false, 3432, 552, 262, 23,
+ 15750, 59886, 54054, 60000, true},
+ {HDMI_VFRMT_2880x480p60_4_3, 2880, 480, false, 3432, 552, 525, 45,
+ 31500, 60000, 108108, 60000, true},
+};
+
+static ssize_t hdmi_edid_sysfs_rda_modes(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ int i;
+ struct hdmi_edid_ctrl *edid_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ buf[0] = 0;
+ if (edid_ctrl->sink_data.num_of_elements) {
+ u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
+ for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+ if (ret > 0)
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
+ *video_mode++ + 1);
+ else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+ *video_mode++ + 1);
+ }
+ } else {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+ edid_ctrl->video_resolution+1);
+ }
+
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+
+ return ret;
+} /* hdmi_edid_sysfs_rda_modes */
+static DEVICE_ATTR(edid_modes, S_IRUGO, hdmi_edid_sysfs_rda_modes, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_physical_address(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_edid_ctrl *edid_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
+ DEV_DBG("%s: '%d'\n", __func__, edid_ctrl->physical_address);
+
+ return ret;
+} /* hdmi_edid_sysfs_rda_physical_address */
+static DEVICE_ATTR(pa, S_IRUGO, hdmi_edid_sysfs_rda_physical_address, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_scan_info(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_edid_ctrl *edid_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
+ edid_ctrl->it_scan_info, edid_ctrl->ce_scan_info);
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+
+ return ret;
+} /* hdmi_edid_sysfs_rda_scan_info */
+static DEVICE_ATTR(scan_info, S_IRUGO, hdmi_edid_sysfs_rda_scan_info, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ int i;
+ char buff_3d[128];
+ struct hdmi_edid_ctrl *edid_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ buf[0] = 0;
+ if (edid_ctrl->sink_data.num_of_elements) {
+ u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
+ u32 *video_3d_mode = edid_ctrl->sink_data.disp_3d_mode_list;
+
+ for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+ ret = hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
+ buff_3d);
+ if (ret > 0)
+ ret += snprintf(buf+ret, PAGE_SIZE-ret,
+ ",%d=%s", *video_mode++ + 1,
+ buff_3d);
+ else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret,
+ "%d=%s", *video_mode++ + 1,
+ buff_3d);
+ }
+ } else {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+ edid_ctrl->video_resolution+1);
+ }
+
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+
+ return ret;
+} /* hdmi_edid_sysfs_rda_3d_modes */
+static DEVICE_ATTR(edid_3d_modes, S_IRUGO, hdmi_edid_sysfs_rda_3d_modes, NULL);
+
+static struct attribute *hdmi_edid_fs_attrs[] = {
+ &dev_attr_edid_modes.attr,
+ &dev_attr_pa.attr,
+ &dev_attr_scan_info.attr,
+ &dev_attr_edid_3d_modes.attr,
+ NULL,
+};
+
+static struct attribute_group hdmi_edid_fs_attrs_group = {
+ .attrs = hdmi_edid_fs_attrs,
+};
+
+static int hdmi_edid_read_block(struct hdmi_edid_ctrl *edid_ctrl, int block,
+ u8 *edid_buf)
+{
+ const u8 *b = NULL;
+ u32 ndx, check_sum, print_len;
+ int block_size = 0x80;
+ int i, status;
+ struct hdmi_tx_ddc_data ddc_data;
+ b = edid_buf;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ do {
+ DEV_DBG("EDID: reading block(%d) with block-size=%d\n",
+ block, block_size);
+ for (i = 0; i < 0x80; i += block_size) {
+ /*Read EDID twice with 32bit alighnment too */
+ if (block < 2) {
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0xA0;
+ ddc_data.offset = block*0x80 + i;
+ ddc_data.data_buf = edid_buf+i;
+ ddc_data.data_len = block_size;
+ ddc_data.retry = 1;
+ ddc_data.what = "EDID";
+ ddc_data.no_align = false;
+
+ status = hdmi_ddc_read(
+ edid_ctrl->init_data.ddc_ctrl,
+ &ddc_data);
+ } else {
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0xA0;
+ ddc_data.offset = block*0x80 + i;
+ ddc_data.data_buf = edid_buf+i;
+ ddc_data.data_len = block_size;
+ ddc_data.request_len = block_size;
+ ddc_data.retry = 1;
+ ddc_data.what = "EDID";
+
+ status = hdmi_ddc_read_seg(
+ edid_ctrl->init_data.ddc_ctrl,
+ &ddc_data);
+ }
+ if (status)
+ break;
+ }
+
+ block_size /= 2;
+ } while (status && (block_size >= 16));
+
+ if (status)
+ goto error;
+
+ /* Calculate checksum */
+ check_sum = 0;
+ for (ndx = 0; ndx < 0x80; ++ndx)
+ check_sum += edid_buf[ndx];
+
+ if (check_sum & 0xFF) {
+ DEV_ERR("%s: failed CHECKSUM (read:%x, expected:%x)\n",
+ __func__, (u8)edid_buf[0x7F], (u8)check_sum);
+ for (ndx = 0; ndx < 0x100; ndx += 4)
+ DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
+ ndx, ndx+3,
+ b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
+ status = -EPROTO;
+ goto error;
+ }
+
+ print_len = 0x80;
+ for (ndx = 0; ndx < print_len; ndx += 16)
+ DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
+ ndx, ndx+3,
+ b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
+
+error:
+ return status;
+} /* hdmi_edid_read_block */
+
+static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
+ u8 type, u8 *len)
+{
+ /* the start of data block collection, start of Video Data Block */
+ u32 offset = start_offset;
+ u32 end_dbc_offset = in_buf[2];
+
+ *len = 0;
+
+ /*
+ * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
+ * collection present.
+ * * edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block
+ * collection present and no DTD data present.
+ */
+ if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) {
+ DEV_WARN("EDID: no DTD or non-DTD data present\n");
+ return NULL;
+ }
+
+ while (offset < end_dbc_offset) {
+ u8 block_len = in_buf[offset] & 0x1F;
+ if ((in_buf[offset] >> 5) == type) {
+ *len = block_len;
+ DEV_DBG("%s: EDID: block=%d found @ %d w/ length=%d\n",
+ __func__, type, offset, block_len);
+
+ return in_buf + offset;
+ }
+ offset += 1 + block_len;
+ }
+ DEV_WARN("%s: EDID: type=%d block not found in EDID block\n",
+ __func__, type);
+
+ return NULL;
+} /* hdmi_edid_find_block */
+
+static void hdmi_edid_extract_extended_data_blocks(
+ struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+ u8 len = 0;
+ u32 start_offset = DBC_START_OFFSET;
+ u8 const *etag = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ /* A Tage code of 7 identifies extended data blocks */
+ etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+
+ while (etag != NULL) {
+ /* The extended data block should at least be 2 bytes long */
+ if (len < 2) {
+ DEV_DBG("%s: data block of len < 2 bytes. Ignor...\n",
+ __func__);
+ } else {
+ /*
+ * The second byte of the extended data block has the
+ * extended tag code
+ */
+ switch (etag[1]) {
+ case 0:
+ /* Video Capability Data Block */
+ DEV_DBG("%s: EDID: VCDB=%02X %02X\n", __func__,
+ etag[1], etag[2]);
+
+ /*
+ * Check if the sink specifies underscan
+ * support for:
+ * BIT 5: preferred video format
+ * BIT 3: IT video format
+ * BIT 1: CE video format
+ */
+ edid_ctrl->pt_scan_info =
+ (etag[2] & (BIT(4) | BIT(5))) >> 4;
+ edid_ctrl->it_scan_info =
+ (etag[2] & (BIT(3) | BIT(2))) >> 2;
+ edid_ctrl->ce_scan_info =
+ etag[2] & (BIT(1) | BIT(0));
+ DEV_DBG("%s: Scan Info (pt|it|ce): (%d|%d|%d)",
+ __func__,
+ edid_ctrl->pt_scan_info,
+ edid_ctrl->it_scan_info,
+ edid_ctrl->ce_scan_info);
+ break;
+ default:
+ DEV_DBG("%s: Tag Code %d not supported\n",
+ __func__, etag[1]);
+ break;
+ }
+ }
+
+ /* There could be more that one extended data block */
+ start_offset = etag - in_buf + len + 1;
+ etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+ }
+} /* hdmi_edid_extract_extended_data_blocks */
+
+static void hdmi_edid_extract_3d_present(struct hdmi_edid_ctrl *edid_ctrl,
+ const u8 *in_buf)
+{
+ u8 len, offset;
+ const u8 *vsd = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+
+ edid_ctrl->present_3d = 0;
+ if (vsd == NULL || len < 9) {
+ DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+ __func__);
+ return;
+ }
+
+ offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+ DEV_DBG("%s: EDID: 3D present @ %d = %02x\n", __func__,
+ offset, vsd[offset]);
+
+ if (vsd[offset] >> 7) { /* 3D format indication present */
+ DEV_INFO("%s: EDID: 3D present, 3D-len=%d\n", __func__,
+ vsd[offset+1] & 0x1F);
+ edid_ctrl->present_3d = 1;
+ }
+} /* hdmi_edid_extract_3d_present */
+
+static void hdmi_edid_extract_audio_data_blocks(
+ struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+ u8 len;
+ const u8 *sad = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
+ if (sad == NULL)
+ return;
+
+ edid_ctrl->audio_data_block_cnt = 0;
+ while (len >= 3 && edid_ctrl->audio_data_block_cnt < 16) {
+ DEV_DBG("%s: ch=%d fmt=%d sampling=0x%02x bitdepth=0x%02x\n",
+ __func__, (sad[1]&0x7)+1, sad[1]>>3, sad[2], sad[3]);
+
+ ++edid_ctrl->audio_data_block_cnt;
+ len -= 3;
+ sad += 3;
+ }
+} /* hdmi_edid_extract_audio_data_blocks */
+
+static void hdmi_edid_extract_speaker_allocation_data(
+ struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+ u8 len;
+ const u8 *sad = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
+ if (sad == NULL)
+ return;
+
+ edid_ctrl->speaker_allocation_block = sad[1];
+ DEV_DBG("%s: EDID: speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
+ __func__, sad[1],
+ (sad[1] & BIT(0)) ? "FL/FR," : "",
+ (sad[1] & BIT(1)) ? "LFE," : "",
+ (sad[1] & BIT(2)) ? "FC," : "",
+ (sad[1] & BIT(3)) ? "RL/RR," : "",
+ (sad[1] & BIT(4)) ? "RC," : "",
+ (sad[1] & BIT(5)) ? "FLC/FRC," : "",
+ (sad[1] & BIT(6)) ? "RLC/RRC," : "");
+} /* hdmi_edid_extract_speaker_allocation_data */
+
+static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
+ const u8 *in_buf)
+{
+ u8 len;
+ const u8 *vsd = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+
+ if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
+ edid_ctrl->video_latency = (u16)-1;
+ edid_ctrl->audio_latency = (u16)-1;
+ DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
+ } else {
+ edid_ctrl->video_latency = vsd[9];
+ edid_ctrl->audio_latency = vsd[10];
+ DEV_DBG("%s: EDID: video-latency=%04x, audio-latency=%04x\n",
+ __func__, edid_ctrl->video_latency,
+ edid_ctrl->audio_latency);
+ }
+} /* hdmi_edid_extract_latency_fields */
+
+static u32 hdmi_edid_extract_ieee_reg_id(struct hdmi_edid_ctrl *edid_ctrl,
+ const u8 *in_buf)
+{
+ u8 len;
+ const u8 *vsd = NULL;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return 0;
+ }
+
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+ if (vsd == NULL)
+ return 0;
+
+ DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
+ ((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
+
+ edid_ctrl->physical_address = ((u16)vsd[4] << 8) + (u16)vsd[5];
+
+ return ((u32)vsd[3] << 16) + ((u32)vsd[2] << 8) + (u32)vsd[1];
+} /* hdmi_edid_extract_ieee_reg_id */
+
+static void hdmi_edid_extract_vendor_id(const u8 *in_buf,
+ char *vendor_id)
+{
+ u32 id_codes = ((u32)in_buf[8] << 8) + in_buf[9];
+
+ vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F);
+ vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F);
+ vendor_id[2] = 'A' - 1 + (id_codes & 0x1F);
+ vendor_id[3] = 0;
+} /* hdmi_edid_extract_vendor_id */
+
+static u32 hdmi_edid_check_header(const u8 *edid_buf)
+{
+ return (edid_buf[0] == 0x00) && (edid_buf[1] == 0xff)
+ && (edid_buf[2] == 0xff) && (edid_buf[3] == 0xff)
+ && (edid_buf[4] == 0xff) && (edid_buf[5] == 0xff)
+ && (edid_buf[6] == 0xff) && (edid_buf[7] == 0x00);
+} /* hdmi_edid_check_header */
+
+static void hdmi_edid_detail_desc(const u8 *data_buf, u32 *disp_mode)
+{
+ u32 aspect_ratio_4_3 = false;
+ u32 interlaced = false;
+ u32 active_h = 0;
+ u32 active_v = 0;
+ u32 blank_h = 0;
+ u32 blank_v = 0;
+ u32 ndx = 0;
+ u32 max_num_of_elements = 0;
+ u32 img_size_h = 0;
+ u32 img_size_v = 0;
+
+ /*
+ * * See VESA Spec
+ * * EDID_TIMING_DESC_UPPER_H_NIBBLE[0x4]: Relative Offset to the
+ * EDID detailed timing descriptors - Upper 4 bit for each H
+ * active/blank field
+ * * EDID_TIMING_DESC_H_ACTIVE[0x2]: Relative Offset to the EDID
+ * detailed timing descriptors - H active
+ */
+ active_h = ((((u32)data_buf[0x4] >> 0x4) & 0xF) << 8)
+ | data_buf[0x2];
+
+ /*
+ * EDID_TIMING_DESC_H_BLANK[0x3]: Relative Offset to the EDID detailed
+ * timing descriptors - H blank
+ */
+ blank_h = (((u32)data_buf[0x4] & 0xF) << 8)
+ | data_buf[0x3];
+
+ /*
+ * * EDID_TIMING_DESC_UPPER_V_NIBBLE[0x7]: Relative Offset to the
+ * EDID detailed timing descriptors - Upper 4 bit for each V
+ * active/blank field
+ * * EDID_TIMING_DESC_V_ACTIVE[0x5]: Relative Offset to the EDID
+ * detailed timing descriptors - V active
+ */
+ active_v = ((((u32)data_buf[0x7] >> 0x4) & 0xF) << 8)
+ | data_buf[0x5];
+
+ /*
+ * EDID_TIMING_DESC_V_BLANK[0x6]: Relative Offset to the EDID
+ * detailed timing descriptors - V blank
+ */
+ blank_v = (((u32)data_buf[0x7] & 0xF) << 8)
+ | data_buf[0x6];
+
+ /*
+ * * EDID_TIMING_DESC_IMAGE_SIZE_UPPER_NIBBLE[0xE]: Relative Offset
+ * to the EDID detailed timing descriptors - Image Size upper
+ * nibble V and H
+ * * EDID_TIMING_DESC_H_IMAGE_SIZE[0xC]: Relative Offset to the EDID
+ * detailed timing descriptors - H image size
+ * * EDID_TIMING_DESC_V_IMAGE_SIZE[0xD]: Relative Offset to the EDID
+ * detailed timing descriptors - V image size
+ */
+ img_size_h = ((((u32)data_buf[0xE] >> 0x4) & 0xF) << 8)
+ | data_buf[0xC];
+ img_size_v = (((u32)data_buf[0xE] & 0xF) << 8)
+ | data_buf[0xD];
+
+ /*
+ * aspect ratio as 4:3 if within specificed range , rathaer than being
+ * absolute value
+ */
+ aspect_ratio_4_3 = (abs(img_size_h * 3 - img_size_v * 4) < 5) ? 1 : 0;
+
+ max_num_of_elements = sizeof(hdmi_edid_disp_mode_lut)
+ / sizeof(*hdmi_edid_disp_mode_lut);
+
+ /*
+ * EDID_TIMING_DESC_INTERLACE[0x11:7]: Relative Offset to the EDID
+ * detailed timing descriptors - Interlace flag
+ */
+ DEV_DBG("%s: Interlaced mode byte data_buf[0x11]=[%x]\n", __func__,
+ data_buf[0x11]);
+
+ /*
+ * CEA 861-D: interlaced bit is bit[7] of byte[0x11]
+ */
+ interlaced = (data_buf[0x11] & 0x80) >> 7;
+
+ DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__,
+ active_h, active_v, blank_h, blank_v, img_size_h, img_size_v,
+ interlaced ? "i" : "p");
+
+ *disp_mode = HDMI_VFRMT_FORCE_32BIT;
+ while (ndx < max_num_of_elements) {
+ const struct hdmi_edid_video_mode_property_type *edid =
+ hdmi_edid_disp_mode_lut + ndx;
+
+ if ((interlaced == edid->interlaced) &&
+ (active_h == edid->active_h) &&
+ (blank_h == edid->total_blank_h) &&
+ (blank_v == edid->total_blank_v) &&
+ ((active_v == edid->active_v) ||
+ (active_v == (edid->active_v + 1)))) {
+ if (edid->aspect_ratio_4_3 && !aspect_ratio_4_3)
+ /* Aspect ratio 16:9 */
+ *disp_mode = edid->video_code + 1;
+ else
+ /* Aspect ratio 4:3 */
+ *disp_mode = edid->video_code;
+
+ DEV_DBG("%s: mode found:%d\n", __func__, *disp_mode);
+ break;
+ }
+ ++ndx;
+ }
+ if (ndx == max_num_of_elements)
+ DEV_INFO("%s: *no mode* found\n", __func__);
+} /* hdmi_edid_detail_desc */
+
+static void hdmi_edid_add_sink_3d_format(struct hdmi_edid_sink_data *sink_data,
+ u32 video_format, u32 video_3d_format)
+{
+ char string[128];
+ u32 added = false;
+ int i;
+
+ for (i = 0; i < sink_data->num_of_elements; ++i) {
+ if (sink_data->disp_mode_list[i] == video_format) {
+ sink_data->disp_3d_mode_list[i] |= video_3d_format;
+ added = true;
+ break;
+ }
+ }
+
+ hdmi_get_video_3d_fmt_2string(video_3d_format, string);
+
+ DEV_DBG("%s: EDID[3D]: format: %d [%s], %s %s\n", __func__,
+ video_format, hdmi_get_video_fmt_2string(video_format),
+ string, added ? "added" : "NOT added");
+} /* hdmi_edid_add_sink_3d_format */
+
+static void hdmi_edid_add_sink_video_format(
+ struct hdmi_edid_sink_data *sink_data, u32 video_format)
+{
+ const struct hdmi_disp_mode_timing_type *timing =
+ hdmi_get_supported_mode(video_format);
+ u32 supported = timing != NULL;
+
+ if (video_format >= HDMI_VFRMT_MAX) {
+ DEV_ERR("%s: video format: %s is not supported\n", __func__,
+ hdmi_get_video_fmt_2string(video_format));
+ return;
+ }
+
+ DEV_DBG("%s: EDID: format: %d [%s], %s\n", __func__,
+ video_format, hdmi_get_video_fmt_2string(video_format),
+ supported ? "Supported" : "Not-Supported");
+
+ if (supported) {
+ /* todo: MHL */
+ sink_data->disp_mode_list[sink_data->num_of_elements++] =
+ video_format;
+ }
+} /* hdmi_edid_add_sink_video_format */
+
+static void hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf,
+ struct hdmi_edid_sink_data *sink_data, u32 num_of_cea_blocks)
+{
+ u8 len, offset, present_multi_3d, hdmi_vic_len, hdmi_3d_len;
+ u16 structure_all, structure_mask;
+ const u8 *vsd = num_of_cea_blocks ?
+ hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+ 3, &len) : NULL;
+ int i;
+
+ offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+ present_multi_3d = (vsd[offset] & 0x60) >> 5;
+
+ offset += 1;
+ hdmi_vic_len = (vsd[offset] >> 5) & 0x7;
+ hdmi_3d_len = vsd[offset] & 0x1F;
+ DEV_DBG("%s: EDID[3D]: HDMI_VIC_LEN = %d, HDMI_3D_LEN = %d\n", __func__,
+ hdmi_vic_len, hdmi_3d_len);
+
+ offset += (hdmi_vic_len + 1);
+ if (present_multi_3d == 1 || present_multi_3d == 2) {
+ DEV_DBG("%s: EDID[3D]: multi 3D present (%d)\n", __func__,
+ present_multi_3d);
+ /* 3d_structure_all */
+ structure_all = (vsd[offset] << 8) | vsd[offset + 1];
+ offset += 2;
+ hdmi_3d_len -= 2;
+ if (present_multi_3d == 2) {
+ /* 3d_structure_mask */
+ structure_mask = (vsd[offset] << 8) | vsd[offset + 1];
+ offset += 2;
+ hdmi_3d_len -= 2;
+ } else
+ structure_mask = 0xffff;
+
+ i = 0;
+ while (i < 16) {
+ if (i >= sink_data->disp_multi_3d_mode_list_cnt)
+ break;
+
+ if (!(structure_mask & BIT(i))) {
+ ++i;
+ continue;
+ }
+
+ /* BIT0: FRAME PACKING */
+ if (structure_all & BIT(0))
+ hdmi_edid_add_sink_3d_format(sink_data,
+ sink_data->
+ disp_multi_3d_mode_list[i],
+ FRAME_PACKING);
+
+ /* BIT6: TOP AND BOTTOM */
+ if (structure_all & BIT(6))
+ hdmi_edid_add_sink_3d_format(sink_data,
+ sink_data->
+ disp_multi_3d_mode_list[i],
+ TOP_AND_BOTTOM);
+
+ /* BIT8: SIDE BY SIDE HALF */
+ if (structure_all & BIT(8))
+ hdmi_edid_add_sink_3d_format(sink_data,
+ sink_data->
+ disp_multi_3d_mode_list[i],
+ SIDE_BY_SIDE_HALF);
+
+ ++i;
+ }
+ }
+
+ i = 0;
+ while (hdmi_3d_len > 0) {
+ DEV_DBG("%s: EDID[3D]: 3D_Structure_%d @ %d: %02x\n", __func__,
+ i + 1, offset, vsd[offset]);
+
+ if ((vsd[offset] >> 4) >=
+ sink_data->disp_multi_3d_mode_list_cnt) {
+ if ((vsd[offset] & 0x0F) >= 8) {
+ offset += 1;
+ hdmi_3d_len -= 1;
+ DEV_DBG("%s:EDID[3D]:3D_Detail_%d @ %d: %02x\n",
+ __func__, i + 1, offset,
+ vsd[offset]);
+ }
+ i += 1;
+ offset += 1;
+ hdmi_3d_len -= 1;
+ continue;
+ }
+
+ switch (vsd[offset] & 0x0F) {
+ case 0:
+ /* 0000b: FRAME PACKING */
+ hdmi_edid_add_sink_3d_format(sink_data,
+ sink_data->
+ disp_multi_3d_mode_list[vsd[offset] >> 4],
+ FRAME_PACKING);
+ break;
+ case 6:
+ /* 0110b: TOP AND BOTTOM */
+ hdmi_edid_add_sink_3d_format(sink_data,
+ sink_data->
+ disp_multi_3d_mode_list[vsd[offset] >> 4],
+ TOP_AND_BOTTOM);
+ break;
+ case 8:
+ /* 1000b: SIDE BY SIDE HALF */
+ hdmi_edid_add_sink_3d_format(sink_data,
+ sink_data->
+ disp_multi_3d_mode_list[vsd[offset] >> 4],
+ SIDE_BY_SIDE_HALF);
+ break;
+ }
+ if ((vsd[offset] & 0x0F) >= 8) {
+ offset += 1;
+ hdmi_3d_len -= 1;
+ DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ %d: %02x\n",
+ __func__, i + 1, offset,
+ vsd[offset]);
+ }
+ i += 1;
+ offset += 1;
+ hdmi_3d_len -= 1;
+ }
+} /* hdmi_edid_get_display_vsd_3d_mode */
+
+static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
+ const u8 *data_buf, u32 num_of_cea_blocks)
+{
+ u8 i = 0;
+ u32 video_format = HDMI_VFRMT_640x480p60_4_3;
+ u32 has480p = false;
+ u8 len;
+ const u8 *edid_blk0 = NULL;
+ const u8 *edid_blk1 = NULL;
+ const u8 *svd = NULL;
+ u32 has60hz_mode = false;
+ u32 has50hz_mode = false;
+ struct hdmi_edid_sink_data *sink_data = NULL;
+
+ if (!edid_ctrl || !data_buf) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ edid_blk0 = &data_buf[0x0];
+ edid_blk1 = &data_buf[0x80];
+ svd = num_of_cea_blocks ?
+ hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2,
+ &len) : NULL;
+
+ sink_data = &edid_ctrl->sink_data;
+
+ sink_data->num_of_elements = 0;
+ sink_data->disp_multi_3d_mode_list_cnt = 0;
+ if (svd != NULL) {
+ ++svd;
+ for (i = 0; i < len; ++i, ++svd) {
+ /*
+ * Subtract 1 because it is zero based in the driver,
+ * while the Video identification code is 1 based in the
+ * CEA_861D spec
+ */
+ video_format = (*svd & 0x7F) - 1;
+ hdmi_edid_add_sink_video_format(sink_data,
+ video_format);
+ /* Make a note of the preferred video format */
+ if (i == 0)
+ sink_data->preferred_video_format =
+ video_format;
+
+ if (i < 16) {
+ sink_data->disp_multi_3d_mode_list[i]
+ = video_format;
+ sink_data->disp_multi_3d_mode_list_cnt++;
+ }
+
+ if (video_format <= HDMI_VFRMT_1920x1080p60_16_9 ||
+ video_format == HDMI_VFRMT_2880x480p60_4_3 ||
+ video_format == HDMI_VFRMT_2880x480p60_16_9)
+ has60hz_mode = true;
+
+ if ((video_format >= HDMI_VFRMT_720x576p50_4_3 &&
+ video_format <= HDMI_VFRMT_1920x1080p50_16_9) ||
+ video_format == HDMI_VFRMT_2880x576p50_4_3 ||
+ video_format == HDMI_VFRMT_2880x576p50_16_9 ||
+ video_format == HDMI_VFRMT_1920x1250i50_16_9)
+ has50hz_mode = true;
+
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = true;
+ }
+ } else if (!num_of_cea_blocks) {
+ /* Detailed timing descriptors */
+ u32 desc_offset = 0;
+ /*
+ * * Maximum 4 timing descriptor in block 0 - No CEA
+ * extension in this case
+ * * EDID_FIRST_TIMING_DESC[0x36] - 1st detailed timing
+ * descriptor
+ * * EDID_DETAIL_TIMING_DESC_BLCK_SZ[0x12] - Each detailed
+ * timing descriptor has block size of 18
+ */
+ while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+ hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+ &video_format);
+
+ DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ hdmi_get_video_fmt_2string(video_format));
+
+ hdmi_edid_add_sink_video_format(sink_data,
+ video_format);
+
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = true;
+
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ sink_data->preferred_video_format =
+ video_format;
+ }
+ desc_offset += 0x12;
+ ++i;
+ }
+ } else if (1 == num_of_cea_blocks) {
+ u32 desc_offset = 0;
+
+ /*
+ * Read from both block 0 and block 1
+ * Read EDID block[0] as above
+ */
+ while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+ hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+ &video_format);
+
+ DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ hdmi_get_video_fmt_2string(video_format));
+
+ hdmi_edid_add_sink_video_format(sink_data,
+ video_format);
+
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = true;
+
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ sink_data->preferred_video_format =
+ video_format;
+ }
+ desc_offset += 0x12;
+ ++i;
+ }
+
+ /*
+ * * Parse block 1 - CEA extension byte offset of first
+ * detailed timing generation - offset is relevant to
+ * the offset of block 1
+ * * EDID_CEA_EXTENSION_FIRST_DESC[0x82]: Offset to CEA
+ * extension first timing desc - indicate the offset of
+ * the first detailed timing descriptor
+ * * EDID_BLOCK_SIZE = 0x80 Each page size in the EDID ROM
+ */
+ desc_offset = edid_blk1[0x02];
+ while (0 != edid_blk1[desc_offset]) {
+ hdmi_edid_detail_desc(edid_blk1+desc_offset,
+ &video_format);
+
+ DEV_DBG("[%s:%d] Block-1 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ hdmi_get_video_fmt_2string(video_format));
+
+ hdmi_edid_add_sink_video_format(sink_data,
+ video_format);
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = true;
+
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ sink_data->preferred_video_format =
+ video_format;
+ }
+ desc_offset += 0x12;
+ ++i;
+ }
+ }
+
+ /* mandaroty 3d format */
+ if (edid_ctrl->present_3d) {
+ if (has60hz_mode) {
+ hdmi_edid_add_sink_3d_format(sink_data,
+ HDMI_VFRMT_1920x1080p24_16_9,
+ FRAME_PACKING | TOP_AND_BOTTOM);
+ hdmi_edid_add_sink_3d_format(sink_data,
+ HDMI_VFRMT_1280x720p60_16_9,
+ FRAME_PACKING | TOP_AND_BOTTOM);
+ hdmi_edid_add_sink_3d_format(sink_data,
+ HDMI_VFRMT_1920x1080i60_16_9,
+ SIDE_BY_SIDE_HALF);
+ }
+
+ if (has50hz_mode) {
+ hdmi_edid_add_sink_3d_format(sink_data,
+ HDMI_VFRMT_1920x1080p24_16_9,
+ FRAME_PACKING | TOP_AND_BOTTOM);
+ hdmi_edid_add_sink_3d_format(sink_data,
+ HDMI_VFRMT_1280x720p50_16_9,
+ FRAME_PACKING | TOP_AND_BOTTOM);
+ hdmi_edid_add_sink_3d_format(sink_data,
+ HDMI_VFRMT_1920x1080i50_16_9,
+ SIDE_BY_SIDE_HALF);
+ }
+
+ /* 3d format described in Vendor Specific Data */
+ hdmi_edid_get_display_vsd_3d_mode(data_buf, sink_data,
+ num_of_cea_blocks);
+ }
+
+ /*
+ * Need to add default 640 by 480 timings, in case not described
+ * in the EDID structure.
+ * All DTV sink devices should support this mode
+ */
+ if (!has480p)
+ hdmi_edid_add_sink_video_format(sink_data,
+ HDMI_VFRMT_640x480p60_4_3);
+} /* hdmi_edid_get_display_mode */
+
+int hdmi_edid_read(void *input)
+{
+ /* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
+ u8 edid_buf[0x80 * 4];
+ u32 cea_extension_ver = 0;
+ u32 num_of_cea_blocks = 0;
+ u32 ieee_reg_id = 0;
+ u32 i = 1;
+ int status = 0;
+ char vendor_id[5];
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ edid_ctrl->pt_scan_info = 0;
+ edid_ctrl->it_scan_info = 0;
+ edid_ctrl->ce_scan_info = 0;
+ edid_ctrl->present_3d = 0;
+ memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
+ memset(edid_buf, 0, sizeof(edid_buf));
+
+ status = hdmi_edid_read_block(edid_ctrl, 0, edid_buf);
+ if (status || !hdmi_edid_check_header(edid_buf)) {
+ if (!status)
+ status = -EPROTO;
+ DEV_ERR("%s: blk0 fail:%d[%02x%02x%02x%02x%02x%02x%02x%02x]\n",
+ __func__, status,
+ edid_buf[0], edid_buf[1], edid_buf[2], edid_buf[3],
+ edid_buf[4], edid_buf[5], edid_buf[6], edid_buf[7]);
+ goto error;
+ }
+ hdmi_edid_extract_vendor_id(edid_buf, vendor_id);
+
+ /* EDID_CEA_EXTENSION_FLAG[0x7E] - CEC extension byte */
+ num_of_cea_blocks = edid_buf[0x7E];
+ DEV_DBG("%s: No. of CEA blocks is [%u]\n", __func__,
+ num_of_cea_blocks);
+ /* Find out any CEA extension blocks following block 0 */
+ switch (num_of_cea_blocks) {
+ case 0: /* No CEA extension */
+ edid_ctrl->sink_mode = false;
+ DEV_DBG("HDMI DVI mode: %s\n",
+ edid_ctrl->sink_mode ? "no" : "yes");
+ break;
+ case 1: /* Read block 1 */
+ status = hdmi_edid_read_block(edid_ctrl, 1, &edid_buf[0x80]);
+ if (status) {
+ DEV_ERR("%s: ddc read block(1) failed: %d\n", __func__,
+ status);
+ goto error;
+ }
+ if (edid_buf[0x80] != 2)
+ num_of_cea_blocks = 0;
+ if (num_of_cea_blocks) {
+ ieee_reg_id =
+ hdmi_edid_extract_ieee_reg_id(edid_ctrl,
+ edid_buf+0x80);
+ if (ieee_reg_id == 0x0c03)
+ edid_ctrl->sink_mode = true;
+ else
+ edid_ctrl->sink_mode = false;
+
+ hdmi_edid_extract_latency_fields(edid_ctrl,
+ edid_buf+0x80);
+ hdmi_edid_extract_speaker_allocation_data(
+ edid_ctrl, edid_buf+0x80);
+ hdmi_edid_extract_audio_data_blocks(edid_ctrl,
+ edid_buf+0x80);
+ hdmi_edid_extract_3d_present(edid_ctrl,
+ edid_buf+0x80);
+ hdmi_edid_extract_extended_data_blocks(edid_ctrl,
+ edid_buf+0x80);
+ }
+ break;
+ case 2:
+ case 3:
+ case 4:
+ for (i = 1; i <= num_of_cea_blocks; i++) {
+ if (!(i % 2)) {
+ status = hdmi_edid_read_block(
+ edid_ctrl, i, edid_buf+0x00);
+ if (status) {
+ DEV_ERR("%s: read blk(%d) failed:%d\n",
+ __func__, i, status);
+ goto error;
+ }
+ } else {
+ status = hdmi_edid_read_block(
+ edid_ctrl, i, edid_buf+0x80);
+ if (status) {
+ DEV_ERR("%s: read blk(%d) failed:%d\n",
+ __func__, i, status);
+ goto error;
+ }
+ }
+ }
+ break;
+ default:
+ DEV_ERR("%s: ddc read failed, not supported multi-blocks: %d\n",
+ __func__, num_of_cea_blocks);
+ status = -EPROTO;
+ goto error;
+ }
+
+ if (num_of_cea_blocks) {
+ /* EDID_CEA_EXTENSION_VERSION[0x81]: Offset to CEA extension
+ * version number - v1,v2,v3 (v1 is seldom, v2 is obsolete,
+ * v3 most common) */
+ cea_extension_ver = edid_buf[0x81];
+ }
+
+ /* EDID_VERSION[0x12] - EDID Version */
+ /* EDID_REVISION[0x13] - EDID Revision */
+ DEV_INFO("%s: V=%d.%d #CEABlks=%d[V%d] ID=%s IEEE=%04x Ext=0x%02x\n",
+ __func__, edid_buf[0x12], edid_buf[0x13],
+ num_of_cea_blocks, cea_extension_ver, vendor_id, ieee_reg_id,
+ edid_buf[0x80]);
+
+ hdmi_edid_get_display_mode(edid_ctrl, edid_buf, num_of_cea_blocks);
+
+ return 0;
+
+error:
+ edid_ctrl->sink_data.num_of_elements = 1;
+ edid_ctrl->sink_data.disp_mode_list[0] = edid_ctrl->video_resolution;
+
+ return status;
+} /* hdmi_edid_read */
+
+/*
+ * If the sink specified support for both underscan/overscan then, by default,
+ * set the underscan bit. Only checking underscan support for preferred
+ * format and cea formats.
+ */
+u8 hdmi_edid_get_sink_scaninfo(void *input, u32 resolution)
+{
+ u8 scaninfo = 0;
+ int use_ce_scan_info = true;
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ goto end;
+ }
+
+ if (resolution == edid_ctrl->sink_data.preferred_video_format) {
+ use_ce_scan_info = false;
+ switch (edid_ctrl->pt_scan_info) {
+ case 0:
+ /*
+ * Need to use the info specified for the corresponding
+ * IT or CE format
+ */
+ DEV_DBG("%s: No underscan info for preferred V fmt\n",
+ __func__);
+ use_ce_scan_info = true;
+ break;
+ case 3:
+ DEV_DBG("%s: Set underscan bit for preferred V fmt\n",
+ __func__);
+ scaninfo = BIT(1);
+ break;
+ default:
+ DEV_DBG("%s: Underscan not set for preferred V fmt\n",
+ __func__);
+ break;
+ }
+ }
+
+ if (use_ce_scan_info) {
+ if (3 == edid_ctrl->ce_scan_info) {
+ DEV_DBG("%s: Setting underscan bit for CE video fmt\n",
+ __func__);
+ scaninfo |= BIT(1);
+ } else {
+ DEV_DBG("%s: Not setting underscan bit for CE V fmt\n",
+ __func__);
+ }
+ }
+
+end:
+ return scaninfo;
+} /* hdmi_edid_get_sink_scaninfo */
+
+u32 hdmi_edid_get_sink_mode(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return 0;
+ }
+
+ return edid_ctrl->sink_mode;
+} /* hdmi_edid_get_sink_mode */
+
+void hdmi_edid_set_video_resolution(void *input, u32 resolution)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ edid_ctrl->video_resolution = resolution;
+
+ if (1 == edid_ctrl->sink_data.num_of_elements)
+ edid_ctrl->sink_data.disp_mode_list[0] = resolution;
+} /* hdmi_edid_set_video_resolution */
+
+void hdmi_edid_deinit(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (edid_ctrl) {
+ sysfs_remove_group(edid_ctrl->init_data.sysfs_kobj,
+ &hdmi_edid_fs_attrs_group);
+ kfree(edid_ctrl);
+ }
+} /* hdmi_edid_deinit */
+
+void *hdmi_edid_init(struct hdmi_edid_init_data *init_data)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = NULL;
+
+ if (!init_data || !init_data->base ||
+ !init_data->mutex || !init_data->sysfs_kobj ||
+ !init_data->ddc_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ goto error;
+ }
+
+ edid_ctrl = kzalloc(sizeof(*edid_ctrl), GFP_KERNEL);
+ if (!edid_ctrl) {
+ DEV_ERR("%s: Out of memory\n", __func__);
+ goto error;
+ }
+
+ edid_ctrl->init_data = *init_data;
+ edid_ctrl->sink_mode = false;
+
+ if (sysfs_create_group(init_data->sysfs_kobj,
+ &hdmi_edid_fs_attrs_group)) {
+ DEV_ERR("%s: EDID sysfs create failed\n", __func__);
+ kfree(edid_ctrl);
+ edid_ctrl = NULL;
+ }
+
+error:
+ return (void *)edid_ctrl;
+} /* hdmi_edid_deinit */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h
new file mode 100644
index 0000000..d10ae49
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __HDMI_EDID_H__
+#define __HDMI_EDID_H__
+
+#include "mdss_hdmi_util.h"
+
+struct hdmi_edid_init_data {
+ void __iomem *base;
+ struct mutex *mutex;
+ struct kobject *sysfs_kobj;
+
+ struct hdmi_tx_ddc_ctrl *ddc_ctrl;
+};
+
+int hdmi_edid_read(void *edid_ctrl);
+u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
+u32 hdmi_edid_get_sink_mode(void *edid_ctrl);
+void hdmi_edid_set_video_resolution(void *edid_ctrl, u32 resolution);
+void hdmi_edid_deinit(void *edid_ctrl);
+void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
+
+#endif /* __HDMI_EDID_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 6317069..b88ff72 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -24,12 +24,24 @@
#include "mdss_fb.h"
#include "mdss_hdmi_tx.h"
+#include "mdss_hdmi_edid.h"
#include "mdss.h"
#include "mdss_panel.h"
#define DRV_NAME "hdmi-tx"
#define COMPATIBLE_NAME "qcom,hdmi-tx"
+#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9;
+
+/* HDMI PHY/PLL bit field macros */
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+
+#define IFRAME_CHECKSUM_32(d) \
+ ((d & 0xff) + ((d >> 8) & 0xff) + \
+ ((d >> 16) & 0xff) + ((d >> 24) & 0xff))
+
+static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
static irqreturn_t hdmi_tx_isr(int irq, void *data);
struct mdss_hw hdmi_tx_hw = {
@@ -48,6 +60,37 @@
}
} /* hdmi_pm_name */
+static u8 hdmi_tx_avi_iframe_lut[][16] = {
+/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
+ 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
+ {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/
+ {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04}, /*02*/
+ {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
+ 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/
+ {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
+ {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
+ 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/
+ {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
+ {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/
+ {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/
+};
+
static const char *hdmi_tx_clk_name(u32 clk)
{
switch (clk) {
@@ -68,6 +111,298 @@
}
} /* hdmi_tx_io_name */
+static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data(
+ struct mdss_panel_data *mpd)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ if (mpd) {
+ hdmi_ctrl = container_of(mpd, struct hdmi_tx_ctrl, panel_data);
+ if (hdmi_ctrl) {
+ hdmi_ctrl->pixel_clk =
+ mpd->panel_info.fbi->var.pixclock;
+ hdmi_ctrl->xres = mpd->panel_info.fbi->var.xres;
+ hdmi_ctrl->yres = mpd->panel_info.fbi->var.yres;
+ } else {
+ DEV_ERR("%s: hdmi_ctrl = NULL\n", __func__);
+ }
+ } else {
+ DEV_ERR("%s: mdss_panel_data = NULL\n", __func__);
+ }
+ return hdmi_ctrl;
+} /* hdmi_tx_get_drvdata_from_panel_data */
+
+static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_sysfs_dev(
+ struct device *device)
+{
+ struct msm_fb_data_type *mfd = NULL;
+ struct mdss_panel_data *panel_data = NULL;
+ struct fb_info *fbi = dev_get_drvdata(device);
+
+ if (fbi) {
+ mfd = (struct msm_fb_data_type *)fbi->par;
+ panel_data = dev_get_platdata(&mfd->pdev->dev);
+
+ return hdmi_tx_get_drvdata_from_panel_data(panel_data);
+ } else {
+ DEV_ERR("%s: fbi = NULL\n", __func__);
+ return NULL;
+ }
+} /* hdmi_tx_get_drvdata_from_sysfs_dev */
+
+/* todo: Fix this. Right now this is declared in hdmi_util.h */
+void *hdmi_get_featuredata_from_sysfs_dev(struct device *device,
+ u32 feature_type)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ if (!device || feature_type > HDMI_TX_FEAT_MAX) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(device);
+ if (hdmi_ctrl)
+ return hdmi_ctrl->feature_data[feature_type];
+ else
+ return NULL;
+
+} /* hdmi_tx_get_featuredata_from_sysfs_dev */
+EXPORT_SYMBOL(hdmi_get_featuredata_from_sysfs_dev);
+
+static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_tx_ctrl *hdmi_ctrl =
+ hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ return ret;
+} /* hdmi_tx_sysfs_rda_connected */
+
+static ssize_t hdmi_tx_sysfs_rda_fake_hpd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_tx_ctrl *hdmi_ctrl =
+ hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ return ret;
+} /* hdmi_tx_sysfs_rda_fake_hpd */
+
+static ssize_t hdmi_tx_sysfs_wta_fake_hpd(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int fake_hpd, rc = 0;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ DEV_DBG("%s:\n", __func__);
+ hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = kstrtoint(buf, 10, &fake_hpd);
+ if (rc) {
+ DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ DEV_INFO("%s: fake_hpd=%d\n", __func__, fake_hpd);
+ if (fake_hpd) {
+ hdmi_ctrl->hpd_state = true;
+
+ /* todo: Remove this once HPD line is available in HW */
+ DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+ if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE))
+ DEV_ERR("%s: failed sending online event\n", __func__);
+ switch_set_state(&hdmi_ctrl->sdev, 1);
+ DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+ hdmi_ctrl->sdev.state);
+ } else {
+ hdmi_ctrl->hpd_state = false;
+
+ /* todo: Remove this once HPD line is available in HW */
+ DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+ if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE))
+ DEV_ERR("%s: failed sending online event\n", __func__);
+ switch_set_state(&hdmi_ctrl->sdev, 0);
+ DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+ hdmi_ctrl->sdev.state);
+ }
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ return ret;
+} /* hdmi_tx_sysfs_wta_fake_hpd */
+
+static ssize_t hdmi_tx_sysfs_rda_hpd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_tx_ctrl *hdmi_ctrl =
+ hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_feature_on);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+
+ return ret;
+} /* hdmi_tx_sysfs_rda_hpd */
+
+static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int hpd, rc = 0;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ DEV_DBG("%s:\n", __func__);
+ hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = kstrtoint(buf, 10, &hpd);
+ if (rc) {
+ DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ /* todo: Remove this once HPD line is available in HW */
+ if (0) {
+ if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+ } else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ } else {
+ rc = -EPERM;
+ ret = rc;
+ }
+ }
+
+ if (!rc) {
+ hdmi_ctrl->hpd_feature_on =
+ (~hdmi_ctrl->hpd_feature_on) & BIT(0);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+ } else {
+ DEV_DBG("%s: '%d' (unchanged)\n", __func__,
+ hdmi_ctrl->hpd_feature_on);
+ }
+
+ return ret;
+} /* hdmi_tx_sysfs_wta_hpd */
+
+static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
+static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
+ hdmi_tx_sysfs_wta_hpd);
+static DEVICE_ATTR(fake_hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_fake_hpd,
+ hdmi_tx_sysfs_wta_fake_hpd);
+
+static struct attribute *hdmi_tx_fs_attrs[] = {
+ &dev_attr_connected.attr,
+ &dev_attr_hpd.attr,
+ &dev_attr_fake_hpd.attr,
+ NULL,
+};
+static struct attribute_group hdmi_tx_fs_attrs_group = {
+ .attrs = hdmi_tx_fs_attrs,
+};
+
+static int hdmi_tx_sysfs_create(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc;
+ struct mdss_panel_info *pinfo = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+ pinfo = &hdmi_ctrl->panel_data.panel_info;
+
+ rc = sysfs_create_group(&pinfo->fbi->dev->kobj,
+ &hdmi_tx_fs_attrs_group);
+ if (rc) {
+ DEV_ERR("%s: failed, rc=%d\n", __func__, rc);
+ return rc;
+ }
+ hdmi_ctrl->kobj = &pinfo->fbi->dev->kobj;
+ DEV_DBG("%s: sysfs group %p\n", __func__, hdmi_ctrl->kobj);
+
+ kobject_uevent(hdmi_ctrl->kobj, KOBJ_ADD);
+ DEV_DBG("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+
+ return 0;
+} /* hdmi_tx_sysfs_create */
+
+static void hdmi_tx_sysfs_remove(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+ if (hdmi_ctrl->kobj)
+ sysfs_remove_group(hdmi_ctrl->kobj, &hdmi_tx_fs_attrs_group);
+ hdmi_ctrl->kobj = NULL;
+} /* hdmi_tx_sysfs_remove */
+
+/* Enable HDMI features */
+static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ struct hdmi_edid_init_data edid_init_data;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ edid_init_data.base = hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base;
+ edid_init_data.mutex = &hdmi_ctrl->mutex;
+ edid_init_data.sysfs_kobj = hdmi_ctrl->kobj;
+ edid_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
+
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] =
+ hdmi_edid_init(&edid_init_data);
+ if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) {
+ DEV_ERR("%s: hdmi_edid_init failed\n", __func__);
+ return -EPERM;
+ }
+ hdmi_edid_set_video_resolution(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+ hdmi_ctrl->video_resolution);
+
+ return 0;
+} /* hdmi_tx_init_features */
+
static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
{
return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
@@ -138,11 +473,76 @@
hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
} /* hdmi_tx_setup_video_mode_lut */
+static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
+ u32 clk_idx)
+{
+ if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ return pdata->clk[clk_idx];
+} /* hdmi_tx_get_clk */
+
+static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
+ u32 clk_idx, unsigned long clk_rate)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ if (!pdata) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ clk = hdmi_tx_get_clk(pdata, clk_idx);
+ if (clk) {
+ rc = clk_set_rate(clk, clk_rate);
+ if (IS_ERR_VALUE(rc))
+ DEV_ERR("%s: failed rc=%d\n", __func__, rc);
+ else
+ DEV_DBG("%s: name='%s' rate=%lu\n", __func__,
+ hdmi_tx_clk_name(clk_idx), clk_rate);
+ } else {
+ DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
+ rc = -EINVAL;
+ }
+
+ return rc;
+} /* hdmi_tx_clk_set_rate */
+
+static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int status;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!hdmi_tx_is_controller_on(hdmi_ctrl)) {
+ DEV_ERR("%s: failed: HDMI controller is off", __func__);
+ status = -ENXIO;
+ goto error;
+ }
+
+ hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl);
+
+ status = hdmi_edid_read(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+ if (!status)
+ DEV_DBG("%s: hdmi_edid_read success\n", __func__);
+ else
+ DEV_ERR("%s: hdmi_edid_read failed\n", __func__);
+
+error:
+ return status;
+} /* hdmi_tx_read_sink_info */
+
static void hdmi_tx_hpd_state_work(struct work_struct *work)
{
u32 hpd_state = false;
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
- struct hdmi_tx_io_data *io = NULL;
+ struct dss_io_data *io = NULL;
hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_state_work);
if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
@@ -181,7 +581,6 @@
}
hdmi_ctrl->hpd_stable = 1;
- DEV_INFO("HDMI HPD: event detected\n");
/*
*todo: Revisit cable chg detected condition when HPD support is ready
@@ -190,6 +589,8 @@
mutex_unlock(&hdmi_ctrl->mutex);
if (hpd_state) {
+ /* todo: what if EDID read fails? */
+ hdmi_tx_read_sink_info(hdmi_ctrl);
DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
switch_set_state(&hdmi_ctrl->sdev, 1);
@@ -235,7 +636,432 @@
return 0;
} /* hdmi_tx_check_capability */
-/* todo: revisit when new HPD debouncing logic is available */
+static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc = 0;
+ const struct hdmi_disp_mode_timing_type *timing = NULL;
+ struct hdmi_tx_platform_data *pdata = NULL;
+ u32 format = DEFAULT_VIDEO_RESOLUTION;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ pdata = &hdmi_ctrl->pdata;
+
+ DEV_DBG("%s: Resolution wanted=%dx%d\n", __func__, hdmi_ctrl->xres,
+ hdmi_ctrl->yres);
+ switch (hdmi_ctrl->xres) {
+ default:
+ case 640:
+ format = HDMI_VFRMT_640x480p60_4_3;
+ break;
+ case 720:
+ format = (hdmi_ctrl->yres == 480)
+ ? HDMI_VFRMT_720x480p60_16_9
+ : HDMI_VFRMT_720x576p50_16_9;
+ break;
+ case 1280:
+ if (hdmi_ctrl->frame_rate == 50000)
+ format = HDMI_VFRMT_1280x720p50_16_9;
+ else
+ format = HDMI_VFRMT_1280x720p60_16_9;
+ break;
+ case 1440:
+ /* interlaced has half of y res. */
+ format = (hdmi_ctrl->yres == 240)
+ ? HDMI_VFRMT_1440x480i60_16_9
+ : HDMI_VFRMT_1440x576i50_16_9;
+ break;
+ case 1920:
+ if (hdmi_ctrl->yres == 540) {/* interlaced */
+ format = HDMI_VFRMT_1920x1080i60_16_9;
+ } else if (hdmi_ctrl->yres == 1080) {
+ if (hdmi_ctrl->frame_rate == 50000)
+ format = HDMI_VFRMT_1920x1080p50_16_9;
+ else if (hdmi_ctrl->frame_rate == 24000)
+ format = HDMI_VFRMT_1920x1080p24_16_9;
+ else if (hdmi_ctrl->frame_rate == 25000)
+ format = HDMI_VFRMT_1920x1080p25_16_9;
+ else if (hdmi_ctrl->frame_rate == 30000)
+ format = HDMI_VFRMT_1920x1080p30_16_9;
+ else
+ format = HDMI_VFRMT_1920x1080p60_16_9;
+ }
+ break;
+ }
+
+ if (hdmi_ctrl->video_resolution != format)
+ DEV_DBG("%s: switching %s => %s", __func__,
+ hdmi_get_video_fmt_2string(
+ hdmi_ctrl->video_resolution),
+ hdmi_get_video_fmt_2string(format));
+ else
+ DEV_DBG("resolution %s", hdmi_get_video_fmt_2string(
+ hdmi_ctrl->video_resolution));
+
+ timing = hdmi_get_supported_mode(format);
+ if (!timing) {
+ DEV_ERR("%s: invalid video fmt=%d\n", __func__,
+ hdmi_ctrl->video_resolution);
+ rc = -EPERM;
+ goto end;
+ }
+
+ /*
+ * extpclk is driven by hdmi phy pll. This phy pll programming requires
+ * hdmi_ahb_clk. So enable it and then disable.
+ */
+ rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
+ if (rc) {
+ DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+ goto end;
+ }
+ rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
+ timing->pixel_freq * 1000);
+ if (rc) {
+ DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+ clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+ goto end;
+ }
+ clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+
+ hdmi_ctrl->video_resolution = format;
+ hdmi_edid_set_video_resolution(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], format);
+
+end:
+ return rc;
+} /* hdmi_tx_set_video_fmt */
+
+static void hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+ int video_format)
+{
+ u32 total_v = 0;
+ u32 total_h = 0;
+ u32 start_h = 0;
+ u32 end_h = 0;
+ u32 start_v = 0;
+ u32 end_v = 0;
+ struct dss_io_data *io = NULL;
+
+ const struct hdmi_disp_mode_timing_type *timing =
+ hdmi_get_supported_mode(video_format);
+ if (timing == NULL) {
+ DEV_ERR("%s: video format not supported: %d\n", __func__,
+ video_format);
+ return;
+ }
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ total_h = timing->active_h + timing->front_porch_h +
+ timing->back_porch_h + timing->pulse_width_h - 1;
+ total_v = timing->active_v + timing->front_porch_v +
+ timing->back_porch_v + timing->pulse_width_v - 1;
+ HDMI_REG_W(io->base, HDMI_TOTAL,
+ ((total_v << 16) & 0x0FFF0000) |
+ ((total_h << 0) & 0x00000FFF));
+
+ start_h = timing->back_porch_h + timing->pulse_width_h;
+ end_h = (total_h + 1) - timing->front_porch_h;
+ HDMI_REG_W(io->base, HDMI_ACTIVE_H,
+ ((end_h << 16) & 0x0FFF0000) |
+ ((start_h << 0) & 0x00000FFF));
+
+ start_v = timing->back_porch_v + timing->pulse_width_v - 1;
+ end_v = total_v - timing->front_porch_v;
+ HDMI_REG_W(io->base, HDMI_ACTIVE_V,
+ ((end_v << 16) & 0x0FFF0000) |
+ ((start_v << 0) & 0x00000FFF));
+
+ if (timing->interlaced) {
+ HDMI_REG_W(io->base, HDMI_V_TOTAL_F2,
+ ((total_v + 1) << 0) & 0x00000FFF);
+
+ HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2,
+ (((start_v + 1) << 0) & 0x00000FFF) |
+ (((end_v + 1) << 16) & 0x0FFF0000));
+ } else {
+ HDMI_REG_W(io->base, HDMI_V_TOTAL_F2, 0);
+ HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2, 0);
+ }
+
+ HDMI_REG_W(io->base, HDMI_FRAME_CTRL,
+ ((timing->interlaced << 31) & 0x80000000) |
+ ((timing->active_low_h << 29) & 0x20000000) |
+ ((timing->active_low_v << 28) & 0x10000000));
+} /* hdmi_tx_video_setup */
+
+static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int i, mode = 0;
+ u8 avi_iframe[16]; /* two header + length + 13 data */
+ u8 checksum;
+ u32 sum, regVal;
+ struct dss_io_data *io = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ switch (hdmi_ctrl->video_resolution) {
+ case HDMI_VFRMT_720x480p60_4_3:
+ mode = 0;
+ break;
+ case HDMI_VFRMT_720x480i60_16_9:
+ mode = 1;
+ break;
+ case HDMI_VFRMT_720x576p50_16_9:
+ mode = 2;
+ break;
+ case HDMI_VFRMT_720x576i50_16_9:
+ mode = 3;
+ break;
+ case HDMI_VFRMT_1280x720p60_16_9:
+ mode = 4;
+ break;
+ case HDMI_VFRMT_1280x720p50_16_9:
+ mode = 5;
+ break;
+ case HDMI_VFRMT_1920x1080p60_16_9:
+ mode = 6;
+ break;
+ case HDMI_VFRMT_1920x1080i60_16_9:
+ mode = 7;
+ break;
+ case HDMI_VFRMT_1920x1080p50_16_9:
+ mode = 8;
+ break;
+ case HDMI_VFRMT_1920x1080i50_16_9:
+ mode = 9;
+ break;
+ case HDMI_VFRMT_1920x1080p24_16_9:
+ mode = 10;
+ break;
+ case HDMI_VFRMT_1920x1080p30_16_9:
+ mode = 11;
+ break;
+ case HDMI_VFRMT_1920x1080p25_16_9:
+ mode = 12;
+ break;
+ case HDMI_VFRMT_640x480p60_4_3:
+ mode = 13;
+ break;
+ case HDMI_VFRMT_720x480p60_16_9:
+ mode = 14;
+ break;
+ case HDMI_VFRMT_720x576p50_4_3:
+ mode = 15;
+ break;
+ default:
+ DEV_INFO("%s: mode %d not supported\n", __func__,
+ hdmi_ctrl->video_resolution);
+ return;
+ }
+
+ /* InfoFrame Type = 82 */
+ avi_iframe[0] = 0x82;
+ /* Version = 2 */
+ avi_iframe[1] = 2;
+ /* Length of AVI InfoFrame = 13 */
+ avi_iframe[2] = 13;
+
+ /* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */
+ avi_iframe[3] = hdmi_tx_avi_iframe_lut[0][mode];
+ avi_iframe[3] |= hdmi_edid_get_sink_scaninfo(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+ hdmi_ctrl->video_resolution);
+
+ /* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */
+ avi_iframe[4] = hdmi_tx_avi_iframe_lut[1][mode];
+ /* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */
+ avi_iframe[5] = hdmi_tx_avi_iframe_lut[2][mode];
+ /* Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0 */
+ avi_iframe[6] = hdmi_tx_avi_iframe_lut[3][mode];
+ /* Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0 */
+ avi_iframe[7] = hdmi_tx_avi_iframe_lut[4][mode];
+ /* Data Byte 06: LSB Line No of End of Top Bar */
+ avi_iframe[8] = hdmi_tx_avi_iframe_lut[5][mode];
+ /* Data Byte 07: MSB Line No of End of Top Bar */
+ avi_iframe[9] = hdmi_tx_avi_iframe_lut[6][mode];
+ /* Data Byte 08: LSB Line No of Start of Bottom Bar */
+ avi_iframe[10] = hdmi_tx_avi_iframe_lut[7][mode];
+ /* Data Byte 09: MSB Line No of Start of Bottom Bar */
+ avi_iframe[11] = hdmi_tx_avi_iframe_lut[8][mode];
+ /* Data Byte 10: LSB Pixel Number of End of Left Bar */
+ avi_iframe[12] = hdmi_tx_avi_iframe_lut[9][mode];
+ /* Data Byte 11: MSB Pixel Number of End of Left Bar */
+ avi_iframe[13] = hdmi_tx_avi_iframe_lut[10][mode];
+ /* Data Byte 12: LSB Pixel Number of Start of Right Bar */
+ avi_iframe[14] = hdmi_tx_avi_iframe_lut[11][mode];
+ /* Data Byte 13: MSB Pixel Number of Start of Right Bar */
+ avi_iframe[15] = hdmi_tx_avi_iframe_lut[12][mode];
+
+ sum = 0;
+ for (i = 0; i < 16; i++)
+ sum += avi_iframe[i];
+ sum &= 0xFF;
+ sum = 256 - sum;
+ checksum = (u8) sum;
+
+ regVal = avi_iframe[5];
+ regVal = regVal << 8 | avi_iframe[4];
+ regVal = regVal << 8 | avi_iframe[3];
+ regVal = regVal << 8 | checksum;
+ HDMI_REG_W(io->base, HDMI_AVI_INFO0, regVal);
+
+ regVal = avi_iframe[9];
+ regVal = regVal << 8 | avi_iframe[8];
+ regVal = regVal << 8 | avi_iframe[7];
+ regVal = regVal << 8 | avi_iframe[6];
+ HDMI_REG_W(io->base, HDMI_AVI_INFO1, regVal);
+
+ regVal = avi_iframe[13];
+ regVal = regVal << 8 | avi_iframe[12];
+ regVal = regVal << 8 | avi_iframe[11];
+ regVal = regVal << 8 | avi_iframe[10];
+ HDMI_REG_W(io->base, HDMI_AVI_INFO2, regVal);
+
+ regVal = avi_iframe[1];
+ regVal = regVal << 16 | avi_iframe[15];
+ regVal = regVal << 8 | avi_iframe[14];
+ HDMI_REG_W(io->base, HDMI_AVI_INFO3, regVal);
+
+ /* 0x3 for AVI InfFrame enable (every frame) */
+ HDMI_REG_W(io->base, HDMI_INFOFRAME_CTRL0,
+ HDMI_REG_R(io->base, HDMI_INFOFRAME_CTRL0) |
+ 0x00000003L);
+} /* hdmi_tx_set_avi_infoframe */
+
+static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ u32 packet_header = 0;
+ u32 check_sum = 0;
+ u32 packet_payload = 0;
+ u32 packet_control = 0;
+
+ u8 *vendor_name = NULL;
+ u8 *product_description = NULL;
+ struct dss_io_data *io = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ vendor_name = hdmi_ctrl->spd_vendor_name;
+ product_description = hdmi_ctrl->spd_product_description;
+
+ /* Setup Packet header and payload */
+ /*
+ * 0x83 InfoFrame Type Code
+ * 0x01 InfoFrame Version Number
+ * 0x19 Length of Source Product Description InfoFrame
+ */
+ packet_header = 0x83 | (0x01 << 8) | (0x19 << 16);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_HDR, packet_header);
+ check_sum += IFRAME_CHECKSUM_32(packet_header);
+
+ packet_payload = (vendor_name[3] & 0x7f)
+ | ((vendor_name[4] & 0x7f) << 8)
+ | ((vendor_name[5] & 0x7f) << 16)
+ | ((vendor_name[6] & 0x7f) << 24);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_1, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* Product Description (7-bit ASCII code) */
+ packet_payload = (vendor_name[7] & 0x7f)
+ | ((product_description[0] & 0x7f) << 8)
+ | ((product_description[1] & 0x7f) << 16)
+ | ((product_description[2] & 0x7f) << 24);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_2, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ packet_payload = (product_description[3] & 0x7f)
+ | ((product_description[4] & 0x7f) << 8)
+ | ((product_description[5] & 0x7f) << 16)
+ | ((product_description[6] & 0x7f) << 24);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_3, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ packet_payload = (product_description[7] & 0x7f)
+ | ((product_description[8] & 0x7f) << 8)
+ | ((product_description[9] & 0x7f) << 16)
+ | ((product_description[10] & 0x7f) << 24);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_4, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ packet_payload = (product_description[11] & 0x7f)
+ | ((product_description[12] & 0x7f) << 8)
+ | ((product_description[13] & 0x7f) << 16)
+ | ((product_description[14] & 0x7f) << 24);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_5, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /*
+ * Source Device Information
+ * 00h unknown
+ * 01h Digital STB
+ * 02h DVD
+ * 03h D-VHS
+ * 04h HDD Video
+ * 05h DVC
+ * 06h DSC
+ * 07h Video CD
+ * 08h Game
+ * 09h PC general
+ */
+ packet_payload = (product_description[15] & 0x7f) | 0x00 << 8;
+ HDMI_REG_W(io->base, HDMI_GENERIC1_6, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* Vendor Name (7bit ASCII code) */
+ packet_payload = ((vendor_name[0] & 0x7f) << 8)
+ | ((vendor_name[1] & 0x7f) << 16)
+ | ((vendor_name[2] & 0x7f) << 24);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+ packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
+ HDMI_REG_W(io->base, HDMI_GENERIC1_0, packet_payload);
+
+ /*
+ * GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
+ * Setup HDMI TX generic packet control
+ * Enable this packet to transmit every frame
+ * Enable HDMI TX engine to transmit Generic packet 1
+ */
+ packet_control = HDMI_REG_R_ND(io->base, HDMI_GEN_PKT_CTRL);
+ packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4));
+ HDMI_REG_W(io->base, HDMI_GEN_PKT_CTRL, packet_control);
+} /* hdmi_tx_set_spd_infoframe */
+
+/* todo: revisit when new HPD debouncing logic is avialble */
static void hdmi_tx_hpd_state_timer(unsigned long data)
{
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
@@ -246,59 +1072,551 @@
DEV_ERR("%s: invalid input\n", __func__);
} /* hdmi_tx_hpd_state_timer */
-static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
- u32 clk_idx)
+static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
{
- if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
+ u32 reg_val = 0;
+
+ if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
- return NULL;
+ return;
}
- return pdata->clk[clk_idx];
-} /* hdmi_tx_get_clk */
+ if (power_on) {
+ /* ENABLE */
+ reg_val |= BIT(0); /* Enable the block */
+ if (hdmi_edid_get_sink_mode(
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) == 0) {
+ if (hdmi_ctrl->present_hdcp)
+ /* HDMI Encryption */
+ reg_val |= BIT(2);
+ reg_val |= BIT(1);
+ } else {
+ if (hdmi_ctrl->present_hdcp)
+ /* HDMI_Encryption_ON */
+ reg_val |= BIT(1) | BIT(2);
+ else
+ reg_val |= BIT(1);
+ }
+ } else {
+ reg_val = BIT(1);
+ }
-static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
- u32 clk_idx, unsigned long clk_rate)
+ HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, HDMI_CTRL,
+ reg_val);
+
+ DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
+ power_on ? "Enable" : "Disable", reg_val);
+} /* hdmi_tx_set_mode */
+
+static int hdmi_tx_clk_update(struct hdmi_tx_platform_data *pdata, u32 clk_idx,
+ u32 enable)
{
int rc = 0;
- struct clk *clk = NULL;
+ struct clk *clk = hdmi_tx_get_clk(pdata, clk_idx);
- if (!pdata) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- clk = hdmi_tx_get_clk(pdata, clk_idx);
if (clk) {
- rc = clk_set_rate(clk, clk_rate);
- if (IS_ERR_VALUE(rc))
- DEV_ERR("%s: failed rc=%d\n", __func__, rc);
- else
- DEV_DBG("%s: clk=%d rate=%lu\n", __func__,
- clk_idx, clk_rate);
+ DEV_DBG("%s: clk=%d en=%d\n", __func__, clk_idx, enable);
+ if (enable) {
+ rc = clk_prepare_enable(clk);
+ if (rc)
+ DEV_ERR("%s: clk=%d enable failed\n",
+ __func__, clk_idx);
+ } else {
+ clk_disable_unprepare(clk);
+ }
} else {
- DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
+ DEV_ERR("%s: FAILED: invalid input for clk='%s'\n", __func__,
+ hdmi_tx_clk_name(clk_idx));
rc = -EINVAL;
}
return rc;
-} /* hdmi_tx_clk_set_rate */
+} /* hdmi_tx_clk_update */
-static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
+/* Note: Before accessing extpclk, always make sure that hdmi_ahb_clk is on */
+static int hdmi_tx_clk_ctrl_update(struct hdmi_tx_platform_data *pdata, int on)
{
- return 0;
-} /* hdmi_tx_power_on */
+ int rc = 0;
+ DEV_DBG("%s: HDMI Clk: %s\n", __func__, on ? "Enable" : "Disable");
+
+ rc = hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, on);
+ if (on && rc) {
+ DEV_ERR("%s: '%s' on failed\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_APP_CLK));
+ goto fail_hdmi_app_clk;
+ }
+ if (on) {
+ rc = hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
+ if (rc) {
+ DEV_ERR("%s: '%s' on failed\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+ goto fail_hdmi_ahb_clk;
+ }
+ rc = hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
+ if (rc) {
+ DEV_ERR("%s: '%s' on failed\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+ goto fail_hdmi_extp_clk;
+ }
+ } else {
+ hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
+ hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
+ }
+ return rc;
+
+fail_hdmi_extp_clk:
+ hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, 0);
+fail_hdmi_ahb_clk:
+ hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, 0);
+fail_hdmi_app_clk:
+ return rc;
+} /* hdmi_tx_clk_ctrl_update */
+
+static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
+ enum hdmi_tx_power_module_type module, int enable)
+{
+ int rc = 0;
+ struct dss_module_power *power_data = NULL;
+
+ if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
+ DEV_ERR("%s: Error: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ power_data = &hdmi_ctrl->pdata.power_data[module];
+ if (!power_data) {
+ DEV_ERR("%s: Error: invalid power data\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (enable) {
+ rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+ power_data->vreg_config, power_data->num_vreg, 1);
+ if (rc) {
+ DEV_ERR("%s: Failed to config %s vreg. Error=%d\n",
+ __func__, hdmi_pm_name(module), rc);
+ return rc;
+ }
+
+ rc = msm_dss_enable_vreg(power_data->vreg_config,
+ power_data->num_vreg, 1);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
+ __func__, hdmi_pm_name(module), rc);
+ goto deconfig_vreg;
+ }
+
+ rc = msm_dss_enable_gpio(power_data->gpio_config,
+ power_data->num_gpio, enable);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
+ __func__, hdmi_pm_name(module), rc);
+ goto disable_vreg;
+ }
+ } else {
+ msm_dss_enable_gpio(power_data->gpio_config,
+ power_data->num_gpio, 0);
+ }
+
+ return rc;
+
+disable_vreg:
+ msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
+deconfig_vreg:
+ msm_dss_config_vreg(&hdmi_ctrl->pdev->dev, power_data->vreg_config,
+ power_data->num_vreg, 0);
+error:
+ return rc;
+} /* hdmi_tx_enable_power */
+
+static void hdmi_tx_core_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 0);
+ hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
+} /* hdmi_tx_core_off */
+
+static int hdmi_tx_core_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc = 0;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 1);
+ if (rc) {
+ DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
+ __func__, rc);
+ goto error;
+ }
+ rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
+ if (rc) {
+ DEV_ERR("%s: cec hdmi_msm_enable_power failed rc = %d\n",
+ __func__, rc);
+ goto disable_core_power;
+ }
+
+ return rc;
+disable_core_power:
+ hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
+error:
+ return rc;
+} /* hdmi_tx_core_on */
+
+static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ unsigned int phy_reset_polarity = 0x0;
+ unsigned int pll_reset_polarity = 0x0;
+ unsigned int val;
+ struct dss_io_data *io = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: io not inititalized\n", __func__);
+ return;
+ }
+
+ val = HDMI_REG_R_ND(io->base, HDMI_PHY_CTRL);
+
+ phy_reset_polarity = val >> 3 & 0x1;
+ pll_reset_polarity = val >> 1 & 0x1;
+
+ if (phy_reset_polarity == 0)
+ HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+ else
+ HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+
+ if (pll_reset_polarity == 0)
+ HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+ else
+ HDMI_REG_W_ND(io->base,
+ HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+
+ if (phy_reset_polarity == 0)
+ HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+ else
+ HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+
+ if (pll_reset_polarity == 0)
+ HDMI_REG_W_ND(io->base,
+ HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+ else
+ HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+} /* hdmi_tx_phy_reset */
+
+static void hdmi_tx_init_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ struct dss_io_data *io = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG0, 0x1B);
+ HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG1, 0xF2);
+ HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_CFG0, 0x0);
+ HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN0, 0x0);
+ HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN1, 0x0);
+ HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN2, 0x0);
+ HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN3, 0x0);
+
+ HDMI_REG_W_ND(io->base, HDMI_PHY_PD_CTRL1, 0x20);
+} /* hdmi_tx_init_phy */
+
+static void hdmi_tx_powerdown_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ HDMI_REG_W_ND(hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO].base,
+ HDMI_PHY_PD_CTRL0, 0x7F);
+} /* hdmi_tx_powerdown_phy */
+
+static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc = 0;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+ /* todo: Audio */
+
+ hdmi_tx_set_mode(hdmi_ctrl, false);
+ mutex_lock(&hdmi_ctrl->mutex);
+ rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 1);
+ if (rc) {
+ DEV_ERR("%s: hdmi_tx_clk_enable failed.\n", __func__);
+ mutex_unlock(&hdmi_ctrl->mutex);
+ return rc;
+ }
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ hdmi_tx_init_phy(hdmi_ctrl);
+ HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+ HDMI_USEC_REFTIMER, 0x0001001B);
+
+ hdmi_tx_set_mode(hdmi_ctrl, true);
+
+ hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+ /* todo: Audio */
+ hdmi_tx_set_avi_infoframe(hdmi_ctrl);
+ /* todo: CONFIG_FB_MSM_HDMI_3D */
+ hdmi_tx_set_spd_infoframe(hdmi_ctrl);
+
+ /* Set IRQ for HPD */
+ HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+ HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
+
+ /* todo: HDCP/CEC */
+
+ DEV_INFO("%s: HDMI Core: Initialized\n", __func__);
+
+ return rc;
+} /* hdmi_tx_start */
static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
{
+ struct hdmi_tx_ctrl *hdmi_ctrl =
+ hdmi_tx_get_drvdata_from_panel_data(panel_data);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ DEV_INFO("%s: power: OFF (audio off, Reset Core)\n", __func__);
+ /* todo: Audio */
+ hdmi_tx_powerdown_phy(hdmi_ctrl);
+ hdmi_ctrl->panel_power_on = false;
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ if (hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0))
+ DEV_ERR("%s: hdmi_tx_clk_disable failed.\n", __func__);
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ hdmi_tx_core_off(hdmi_ctrl);
+
return 0;
} /* hdmi_tx_power_off */
+static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
+{
+ int rc = 0;
+ struct hdmi_tx_ctrl *hdmi_ctrl =
+ hdmi_tx_get_drvdata_from_panel_data(panel_data);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = hdmi_tx_core_on(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
+ return rc;
+ }
+
+ DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
+ hdmi_ctrl->pixel_clk);
+
+ rc = hdmi_tx_set_video_fmt(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
+ hdmi_tx_core_off(hdmi_ctrl);
+ return rc;
+ }
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ hdmi_ctrl->panel_power_on = true;
+
+ /* todo: check hdmi_tx_is_controller_on when hpd is on */
+ if (hdmi_ctrl->hpd_state) {
+ DEV_DBG("%s: Turning HDMI on\n", __func__);
+ mutex_unlock(&hdmi_ctrl->mutex);
+ rc = hdmi_tx_start(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: hdmi_tx_start failed. rc=%d\n",
+ __func__, rc);
+ hdmi_tx_power_off(panel_data);
+ return rc;
+ }
+ /* todo: HDCP */
+ } else {
+ mutex_unlock(&hdmi_ctrl->mutex);
+ }
+
+ hdmi_reg_dump(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+ hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len, "HDMI-ON: ");
+
+ DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__,
+ hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" ,
+ hdmi_tx_is_dvi_mode(hdmi_ctrl) ? "ON" : "OFF");
+
+ return 0;
+} /* hdmi_tx_power_on */
+
+static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc = 0;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (!hdmi_ctrl->hpd_initialized) {
+ DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
+ return;
+ }
+
+ DEV_DBG("%s: (timer, 5V, IRQ off)\n", __func__);
+ del_timer_sync(&hdmi_ctrl->hpd_state_timer);
+ mdss_disable_irq(&hdmi_tx_hw);
+
+ hdmi_tx_set_mode(hdmi_ctrl, false);
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0);
+ if (rc)
+ DEV_INFO("%s: Failed to disable clock. Error=%d\n",
+ __func__, rc);
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
+ if (rc)
+ DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
+ __func__, rc);
+
+ hdmi_ctrl->hpd_initialized = false;
+} /* hdmi_tx_hpd_off */
+
+static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ u32 reg_val;
+ int rc = 0;
+ struct dss_io_data *io = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: io not inititalized\n", __func__);
+ return -EINVAL;
+ }
+
+ if (hdmi_ctrl->hpd_initialized) {
+ DEV_DBG("%s: HPD is already ON\n", __func__);
+ } else {
+ rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, true);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable hpd power. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, true);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable clocks. rc=%d\n",
+ __func__, rc);
+ mutex_unlock(&hdmi_ctrl->mutex);
+ goto disable_hpd_power;
+ }
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ hdmi_reg_dump(io->base, io->len, "HDMI-INIT: ");
+
+ hdmi_tx_set_mode(hdmi_ctrl, false);
+ hdmi_tx_phy_reset(hdmi_ctrl);
+ hdmi_tx_set_mode(hdmi_ctrl, true);
+
+ HDMI_REG_W(io->base, HDMI_USEC_REFTIMER, 0x0001001B);
+
+ /* set timeout to 4.1ms (max) for hardware debounce */
+ reg_val = HDMI_REG_R(io->base, HDMI_HPD_CTRL) | 0x1FFF;
+
+ /* Toggle HPD circuit to trigger HPD sense */
+ HDMI_REG_W(io->base, HDMI_HPD_CTRL,
+ ~(1 << 28) & reg_val);
+ HDMI_REG_W(io->base, HDMI_HPD_CTRL, (1 << 28) | reg_val);
+
+ hdmi_ctrl->hpd_initialized = true;
+
+ /* Check HPD State */
+ mdss_enable_irq(&hdmi_tx_hw);
+ }
+
+ /* Set HPD state machine: ensure at least 2 readouts */
+ mutex_lock(&hdmi_ctrl->mutex);
+ hdmi_ctrl->hpd_stable = 0;
+ hdmi_ctrl->hpd_prev_state = true;
+ hdmi_ctrl->hpd_state = false;
+ hdmi_ctrl->hpd_cable_chg_detected = true;
+ mutex_unlock(&hdmi_ctrl->mutex);
+ mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+ return 0;
+
+disable_hpd_power:
+ hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, false);
+
+ return rc;
+} /* hdmi_tx_hpd_on */
+
+static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on)
+{
+ int rc = 0;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ DEV_INFO("%s: %d\n", __func__, on);
+ if (on) {
+ rc = hdmi_tx_hpd_on(hdmi_ctrl);
+ } else {
+ hdmi_tx_hpd_off(hdmi_ctrl);
+ /* Set HDMI switch node to 0 on HPD feature disable */
+ switch_set_state(&hdmi_ctrl->sdev, 0);
+ DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+ hdmi_ctrl->sdev.state);
+ }
+
+ return rc;
+} /* hdmi_tx_sysfs_enable_hpd */
+
static irqreturn_t hdmi_tx_isr(int irq, void *data)
{
u32 hpd_int_status;
u32 hpd_int_ctrl;
- struct hdmi_tx_io_data *io = NULL;
+ struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
@@ -339,6 +1657,9 @@
return IRQ_HANDLED;
}
+ if (!hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
+ return IRQ_HANDLED;
+
DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
hpd_int_status);
@@ -400,26 +1721,6 @@
}
pdata->clk[HDMI_TX_EXTP_CLK] = clk;
- /*
- * extpclk src is hdmi phy pll. This phy pll programming requires
- * hdmi_ahb_clk. So enable it and then disable.
- */
- rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
- if (rc) {
- DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
- goto error;
- }
- rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
- HDMI_TX_EXTP_CLK_DEFAULT);
- if (rc) {
- DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
- clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
- goto error;
- }
- clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
-
return rc;
error:
@@ -434,8 +1735,11 @@
return;
}
+ if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID])
+ hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+
switch_dev_unregister(&hdmi_ctrl->sdev);
- del_timer(&hdmi_ctrl->hpd_state_timer);
+ del_timer_sync(&hdmi_ctrl->hpd_state_timer);
if (hdmi_ctrl->workq)
destroy_workqueue(hdmi_ctrl->workq);
mutex_destroy(&hdmi_ctrl->mutex);
@@ -472,6 +1776,10 @@
goto fail_create_workq;
}
+ /* todo: May be move this ? */
+ hdmi_ctrl->ddc_ctrl.base = pdata->io[HDMI_TX_CORE_IO].base;
+ init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
+
INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
init_timer(&hdmi_ctrl->hpd_state_timer);
hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
@@ -487,7 +1795,7 @@
return 0;
fail_switch_dev:
- del_timer(&hdmi_ctrl->hpd_state_timer);
+ del_timer_sync(&hdmi_ctrl->hpd_state_timer);
fail_create_workq:
if (hdmi_ctrl->workq)
destroy_workqueue(hdmi_ctrl->workq);
@@ -508,7 +1816,7 @@
hdmi_ctrl->panel_data.on = hdmi_tx_power_on;
hdmi_ctrl->panel_data.off = hdmi_tx_power_off;
- hdmi_ctrl->video_resolution = HDMI_VFRMT_1920x1080p60_16_9;
+ hdmi_ctrl->video_resolution = DEFAULT_VIDEO_RESOLUTION;
rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution,
&hdmi_ctrl->panel_data.panel_info);
if (rc) {
@@ -806,7 +2114,6 @@
if (strnstr(st, mod_name, strlen(st))) {
ndx_mask |= BIT(i);
mod_gpio_total++;
- continue;
}
}
@@ -863,47 +2170,6 @@
return rc;
} /* hdmi_tx_get_dt_gpio_data */
-static struct resource *hdmi_tx_get_res_byname(struct platform_device *pdev,
- unsigned int type, const char *name)
-{
- struct resource *res = NULL;
-
- res = platform_get_resource_byname(pdev, type, name);
- if (!res)
- DEV_ERR("%s: '%s' resource not found\n", __func__, name);
-
- return res;
-} /* hdmi_tx_get_res_byname */
-
-static int hdmi_tx_ioremap_byname(struct platform_device *pdev,
- struct hdmi_tx_io_data *io_data, u32 io_type)
-{
- struct resource *res = NULL;
-
- if (!pdev) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- res = hdmi_tx_get_res_byname(pdev, IORESOURCE_MEM,
- hdmi_tx_io_name(io_type));
- if (!res) {
- DEV_ERR("%s: '%s' hdmi_tx_get_res_byname failed\n", __func__,
- hdmi_tx_io_name(io_type));
- return -ENODEV;
- }
-
- io_data->len = resource_size(res);
- io_data->base = ioremap(res->start, io_data->len);
- if (!io_data->base) {
- DEV_ERR("%s: '%s' ioremap failed\n", __func__,
- hdmi_tx_io_name(io_type));
- return -EIO;
- }
-
- return 0;
-} /* hdmi_tx_ioremap_byname */
-
static void hdmi_tx_put_dt_data(struct device *dev,
struct hdmi_tx_platform_data *pdata)
{
@@ -952,7 +2218,8 @@
/* IO */
for (i = 0; i < HDMI_TX_MAX_IO; i++) {
- rc = hdmi_tx_ioremap_byname(pdev, &pdata->io[i], i);
+ rc = msm_dss_ioremap_byname(pdev, &pdata->io[i],
+ hdmi_tx_io_name(i));
if (rc) {
DEV_ERR("%s: '%s' remap failed\n", __func__,
hdmi_tx_io_name(i));
@@ -1040,8 +2307,23 @@
goto failed_reg_panel;
}
+ rc = hdmi_tx_sysfs_create(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: hdmi_tx_sysfs_create failed.rc=%d\n",
+ __func__, rc);
+ goto failed_reg_panel;
+ }
+
+ rc = hdmi_tx_init_features(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: init_features failed.rc=%d\n", __func__, rc);
+ goto failed_init_features;
+ }
+
return rc;
+failed_init_features:
+ hdmi_tx_sysfs_remove(hdmi_ctrl);
failed_reg_panel:
hdmi_tx_dev_deinit(hdmi_ctrl);
failed_dev_init:
@@ -1060,6 +2342,7 @@
return -ENODEV;
}
+ hdmi_tx_sysfs_remove(hdmi_ctrl);
hdmi_tx_dev_deinit(hdmi_ctrl);
hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata);
devm_kfree(&hdmi_ctrl->pdev->dev, hdmi_ctrl);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 2e175ee..7e37d28 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -17,11 +17,6 @@
#include "mdss_hdmi_util.h"
#include "mdss_io_util.h"
-#define HDMI_TX_EXTP_CLK_DEFAULT 148500000
-#define HDMI_TX_EXTP_CLK_LOW 148500000
-#define HDMI_TX_EXTP_CLK_NOMINAL 297000000
-#define HDMI_TX_EXTP_CLK_TURBO 297000000 /* ToDo: Find correct value */
-
enum hdmi_tx_clk_type {
HDMI_TX_AHB_CLK,
HDMI_TX_APP_CLK,
@@ -43,14 +38,9 @@
HDMI_TX_MAX_PM
};
-struct hdmi_tx_io_data {
- u32 len;
- void __iomem *base;
-};
-
struct hdmi_tx_platform_data {
/* Data filled from device tree nodes */
- struct hdmi_tx_io_data io[HDMI_TX_MAX_IO];
+ struct dss_io_data io[HDMI_TX_MAX_IO];
struct dss_module_power power_data[HDMI_TX_MAX_PM];
/* clk and regulator handles */
@@ -88,6 +78,10 @@
u8 spd_vendor_name[8];
u8 spd_product_description[16];
+
+ struct hdmi_tx_ddc_ctrl ddc_ctrl;
+
+ void *feature_data[HDMI_TX_FEAT_MAX];
};
#endif /* __MDSS_HDMI_TX_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index e86f32b..3ba9f89 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -446,8 +446,8 @@
const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
{
switch (format) {
- case TOP_AND_BOTTOM: return "TAB";
- case FRAME_PACKING: return "FP";
+ case TOP_AND_BOTTOM: return "TAB";
+ case FRAME_PACKING: return "FP";
case SIDE_BY_SIDE_HALF: return "SSH";
}
return "";
@@ -483,3 +483,625 @@
return len;
} /* hdmi_get_video_3d_fmt_2string */
+
+static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data,
+ const char *caller)
+{
+ if (!ddc_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ DEV_DBG("%s: buf=%p, d_len=0x%x, d_addr=0x%x, no_align=%d\n",
+ caller, ddc_data->data_buf, ddc_data->data_len,
+ ddc_data->dev_addr, ddc_data->no_align);
+ DEV_DBG("%s: offset=0x%x, req_len=0x%x, retry=%d, what=%s\n",
+ caller, ddc_data->offset, ddc_data->request_len,
+ ddc_data->retry, ddc_data->what);
+} /* hdmi_ddc_print_data */
+
+static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+ char *what)
+{
+ u32 reg_val, time_out_count;
+
+ if (!ddc_ctrl || !ddc_ctrl->base) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ /* clear pending and enable interrupt */
+ time_out_count = 0xFFFF;
+ do {
+ --time_out_count;
+ /* Clear and Enable DDC interrupt */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+ BIT(2) | BIT(1));
+ reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+ } while ((reg_val & BIT(0)) && time_out_count);
+
+ if (!time_out_count) {
+ DEV_ERR("%s[%s]: timedout\n", __func__, what);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+} /*hdmi_ddc_clear_irq */
+
+static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+ struct hdmi_tx_ddc_data *ddc_data)
+{
+ u32 reg_val, ndx, time_out_count;
+ int status = 0;
+ int log_retry_fail;
+
+ if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ddc_data->data_buf) {
+ status = -EINVAL;
+ DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+ goto error;
+ }
+
+ hdmi_ddc_print_data(ddc_data, __func__);
+
+ log_retry_fail = ddc_data->retry != 1;
+again:
+ status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+ if (status)
+ goto error;
+
+ /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+ ddc_data->dev_addr &= 0xFE;
+
+ /*
+ * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #1
+ * DATA_RW = 0x0 (write)
+ * DATA = linkAddress (primary link address and writing)
+ * INDEX = 0x0 (initial offset into buffer)
+ * INDEX_WRITE = 0x1 (setting initial offset)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ BIT(31) | (ddc_data->dev_addr << 8));
+
+ /*
+ * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #2
+ * DATA_RW = 0x0 (write)
+ * DATA = offsetAddress
+ * INDEX = 0x0
+ * INDEX_WRITE = 0x0 (auto-increment by hardware)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+
+ /*
+ * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #3
+ * DATA_RW = 0x0 (write)
+ * DATA = linkAddress + 1 (primary link address 0x74 and reading)
+ * INDEX = 0x0
+ * INDEX_WRITE = 0x0 (auto-increment by hardware)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ (ddc_data->dev_addr | BIT(0)) << 8);
+
+ /* Data setup is complete, now setup the transaction characteristics */
+
+ /*
+ * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+ * order to handle characteristics of portion #1 and portion #2
+ * RW0 = 0x0 (write)
+ * START0 = 0x1 (insert START bit)
+ * STOP0 = 0x0 (do NOT insert STOP bit)
+ * CNT0 = 0x1 (single byte transaction excluding address)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+ /*
+ * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+ * order to handle characteristics of portion #3
+ * RW1 = 0x1 (read)
+ * START1 = 0x1 (insert START bit)
+ * STOP1 = 0x1 (insert STOP bit)
+ * CNT1 = data_len (it's 128 (0x80) for a blk read)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+ BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
+
+ /* Trigger the I2C transfer */
+
+ /*
+ * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+ * Note that NOTHING has been transmitted on the DDC lines up to this
+ * point.
+ * TRANSACTION_CNT = 0x1 (execute transaction0 followed by
+ * transaction1)
+ * SEND_RESET = Set to 1 to send reset sequence
+ * GO = 0x1 (kicks off hardware)
+ */
+ INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+
+ time_out_count = wait_for_completion_interruptible_timeout(
+ &ddc_ctrl->ddc_sw_done, HZ/2);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, BIT(1));
+ if (!time_out_count) {
+ if (ddc_data->retry-- > 0) {
+ DEV_INFO("%s: failed timout, retry=%d\n", __func__,
+ ddc_data->retry);
+ goto again;
+ }
+ status = -ETIMEDOUT;
+ DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+ DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+ __func__,
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+ goto error;
+ }
+
+ /* Read DDC status */
+ reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+ reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+ /* Check if any NACK occurred */
+ if (reg_val) {
+ /* SW_STATUS_RESET */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+
+ if (ddc_data->retry == 1)
+ /* SOFT_RESET */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+
+ if (ddc_data->retry-- > 0) {
+ DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
+ __func__, ddc_data->what, reg_val,
+ ddc_data->retry);
+ DEV_DBG("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+ __func__, ddc_data->dev_addr,
+ ddc_data->offset, ddc_data->data_len);
+ goto again;
+ }
+ status = -EIO;
+ if (log_retry_fail) {
+ DEV_ERR("%s(%s): failed NACK=0x%08x\n",
+ __func__, ddc_data->what, reg_val);
+ DEV_ERR("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+ __func__, ddc_data->dev_addr,
+ ddc_data->offset, ddc_data->data_len);
+ }
+ goto error;
+ }
+
+ /*
+ * 8. ALL data is now available and waiting in the DDC buffer.
+ * Read HDMI_I2C_DATA with the following fields set
+ * RW = 0x1 (read)
+ * DATA = BCAPS (this is field where data is pulled from)
+ * INDEX = 0x3 (where the data has been placed in buffer by hardware)
+ * INDEX_WRITE = 0x1 (explicitly define offset)
+ */
+ /* Write this data to DDC buffer */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ BIT(0) | (3 << 16) | BIT(31));
+
+ /* Discard first byte */
+ HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+ reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ ddc_data->data_buf[ndx] = (u8)((reg_val & 0x0000FF00) >> 8);
+ }
+
+ DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+ return status;
+} /* hdmi_ddc_read_retry */
+
+void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
+{
+ if (!ddc_ctrl || !ddc_ctrl->base) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ /* Configure Pre-Scale multiplier & Threshold */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
+
+ /*
+ * Setting 31:24 bits : Time units to wait before timeout
+ * when clock is being stalled by external sink device
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SETUP, 0xFF000000);
+
+ /* Enable reference timer to 27 micro-seconds */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+} /* hdmi_ddc_config */
+
+int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
+{
+ int rc = -1;
+ u32 ddc_int_ctrl;
+
+ if (!ddc_ctrl || !ddc_ctrl->base) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ddc_int_ctrl = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+ if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) {
+ /* SW_DONE INT occured, clr it */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+ ddc_int_ctrl | BIT(1));
+ complete(&ddc_ctrl->ddc_sw_done);
+ return 0;
+ }
+
+ DEV_DBG("%s: ddc_int_ctrl=%04x\n", __func__, ddc_int_ctrl);
+
+ return rc;
+} /* hdmi_ddc_isr */
+
+int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+ struct hdmi_tx_ddc_data *ddc_data)
+{
+ int rc = 0;
+
+ if (!ddc_ctrl || !ddc_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+ if (!rc)
+ return rc;
+
+ if (ddc_data->no_align) {
+ rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+ } else {
+ ddc_data->request_len = 32 * ((ddc_data->data_len + 31) / 32);
+ rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+ }
+
+ return rc;
+} /* hdmi_ddc_read */
+
+int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+ struct hdmi_tx_ddc_data *ddc_data)
+{
+ int status = 0;
+ u32 reg_val, ndx, time_out_count;
+ int log_retry_fail;
+ int seg_addr = 0x60, seg_num = 0x01;
+
+ if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ddc_data->data_buf) {
+ status = -EINVAL;
+ DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+ goto error;
+ }
+
+ log_retry_fail = ddc_data->retry != 1;
+
+again:
+ status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+ if (status)
+ goto error;
+
+ /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+ ddc_data->dev_addr &= 0xFE;
+
+ /*
+ * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #1
+ * DATA_RW = 0x0 (write)
+ * DATA = linkAddress (primary link address and writing)
+ * INDEX = 0x0 (initial offset into buffer)
+ * INDEX_WRITE = 0x1 (setting initial offset)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
+
+ /*
+ * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #2
+ * DATA_RW = 0x0 (write)
+ * DATA = offsetAddress
+ * INDEX = 0x0
+ * INDEX_WRITE = 0x0 (auto-increment by hardware)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, seg_num << 8);
+
+ /*
+ * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #3
+ * DATA_RW = 0x0 (write)
+ * DATA = linkAddress + 1 (primary link address 0x74 and reading)
+ * INDEX = 0x0
+ * INDEX_WRITE = 0x0 (auto-increment by hardware)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ (ddc_data->dev_addr | BIT(0)) << 8);
+
+ /* Data setup is complete, now setup the transaction characteristics */
+
+ /*
+ * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+ * order to handle characteristics of portion #1 and portion #2
+ * RW0 = 0x0 (write)
+ * START0 = 0x1 (insert START bit)
+ * STOP0 = 0x0 (do NOT insert STOP bit)
+ * CNT0 = 0x1 (single byte transaction excluding address)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+ /*
+ * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+ * order to handle characteristics of portion #3
+ * RW1 = 0x1 (read)
+ * START1 = 0x1 (insert START bit)
+ * STOP1 = 0x1 (insert STOP bit)
+ * CNT1 = data_len (it's 128 (0x80) for a blk read)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
+
+ /*
+ * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+ * order to handle characteristics of portion #3
+ * RW1 = 0x1 (read)
+ * START1 = 0x1 (insert START bit)
+ * STOP1 = 0x1 (insert STOP bit)
+ * CNT1 = data_len (it's 128 (0x80) for a blk read)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS2,
+ BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
+
+ /* Trigger the I2C transfer */
+
+ /*
+ * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+ * Note that NOTHING has been transmitted on the DDC lines up to this
+ * point.
+ * TRANSACTION_CNT = 0x2 (execute transaction0 followed by
+ * transaction1)
+ * GO = 0x1 (kicks off hardware)
+ */
+ INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(21));
+
+ time_out_count = wait_for_completion_interruptible_timeout(
+ &ddc_ctrl->ddc_sw_done, HZ/2);
+
+ reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+ if (!time_out_count) {
+ if (ddc_data->retry-- > 0) {
+ DEV_INFO("%s: failed timout, retry=%d\n", __func__,
+ ddc_data->retry);
+ goto again;
+ }
+ status = -ETIMEDOUT;
+ DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+ DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+ __func__,
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+ goto error;
+ }
+
+ /* Read DDC status */
+ reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+ reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+ /* Check if any NACK occurred */
+ if (reg_val) {
+ /* SW_STATUS_RESET */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+ if (ddc_data->retry == 1)
+ /* SOFT_RESET */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+ if (ddc_data->retry-- > 0) {
+ DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
+ __func__, ddc_data->what, reg_val,
+ ddc_data->retry);
+ DEV_DBG("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+ __func__, ddc_data->dev_addr,
+ ddc_data->offset, ddc_data->data_len);
+ goto again;
+ }
+ status = -EIO;
+ if (log_retry_fail) {
+ DEV_ERR("%s(%s): failed NACK=0x%08x\n",
+ __func__, ddc_data->what, reg_val);
+ DEV_ERR("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+ __func__, ddc_data->dev_addr,
+ ddc_data->offset, ddc_data->data_len);
+ }
+ goto error;
+ }
+
+ /*
+ * 8. ALL data is now available and waiting in the DDC buffer.
+ * Read HDMI_I2C_DATA with the following fields set
+ * RW = 0x1 (read)
+ * DATA = BCAPS (this is field where data is pulled from)
+ * INDEX = 0x5 (where the data has been placed in buffer by hardware)
+ * INDEX_WRITE = 0x1 (explicitly define offset)
+ */
+ /* Write this data to DDC buffer */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ BIT(0) | (5 << 16) | BIT(31));
+
+ /* Discard first byte */
+ HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+
+ for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+ reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ ddc_data->data_buf[ndx] = (u8) ((reg_val & 0x0000FF00) >> 8);
+ }
+
+ DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+ return status;
+} /* hdmi_ddc_read_seg */
+
+int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+ struct hdmi_tx_ddc_data *ddc_data)
+{
+ u32 reg_val, ndx;
+ int status = 0, retry = 10;
+ u32 time_out_count;
+
+ if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ddc_data->data_buf) {
+ status = -EINVAL;
+ DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+ goto error;
+ }
+
+again:
+ status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+ if (status)
+ goto error;
+
+ /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+ ddc_data->dev_addr &= 0xFE;
+
+ /*
+ * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #1
+ * DATA_RW = 0x1 (write)
+ * DATA = linkAddress (primary link address and writing)
+ * INDEX = 0x0 (initial offset into buffer)
+ * INDEX_WRITE = 0x1 (setting initial offset)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ BIT(31) | (ddc_data->dev_addr << 8));
+
+ /*
+ * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #2
+ * DATA_RW = 0x0 (write)
+ * DATA = offsetAddress
+ * INDEX = 0x0
+ * INDEX_WRITE = 0x0 (auto-increment by hardware)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+
+ /*
+ * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+ * handle portion #3
+ * DATA_RW = 0x0 (write)
+ * DATA = data_buf[ndx]
+ * INDEX = 0x0
+ * INDEX_WRITE = 0x0 (auto-increment by hardware)
+ */
+ for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ ((u32)ddc_data->data_buf[ndx]) << 8);
+
+ /* Data setup is complete, now setup the transaction characteristics */
+
+ /*
+ * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+ * order to handle characteristics of portion #1 and portion #2
+ * RW0 = 0x0 (write)
+ * START0 = 0x1 (insert START bit)
+ * STOP0 = 0x0 (do NOT insert STOP bit)
+ * CNT0 = 0x1 (single byte transaction excluding address)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+ /*
+ * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+ * order to handle characteristics of portion #3
+ * RW1 = 0x1 (read)
+ * START1 = 0x1 (insert START bit)
+ * STOP1 = 0x1 (insert STOP bit)
+ * CNT1 = data_len (0xN (write N bytes of data))
+ * Byte count for second transition (excluding the first
+ * Byte which is usually the address)
+ */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+ BIT(13) | ((ddc_data->data_len-1) << 16));
+
+ /* Trigger the I2C transfer */
+ /*
+ * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+ * Note that NOTHING has been transmitted on the DDC lines up to this
+ * point.
+ * TRANSACTION_CNT = 0x1 (execute transaction0 followed by
+ * transaction1)
+ * GO = 0x1 (kicks off hardware)
+ */
+ INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+
+ time_out_count = wait_for_completion_interruptible_timeout(
+ &ddc_ctrl->ddc_sw_done, HZ/2);
+
+ reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+ if (!time_out_count) {
+ if (retry-- > 0) {
+ DEV_INFO("%s[%s]: failed timout, retry=%d\n", __func__,
+ ddc_data->what, retry);
+ goto again;
+ }
+ status = -ETIMEDOUT;
+ DEV_ERR("%s[%s]: timedout, Int Ctrl=%08x\n",
+ __func__, ddc_data->what,
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+ DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+ __func__,
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+ HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+ goto error;
+ }
+
+ /* Read DDC status */
+ reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+ reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000;
+
+ /* Check if any NACK occurred */
+ if (reg_val) {
+ if (retry > 1)
+ /* SW_STATUS_RESET */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+ else
+ /* SOFT_RESET */
+ HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+
+ if (retry-- > 0) {
+ DEV_DBG("%s[%s]: failed NACK=%08x, retry=%d\n",
+ __func__, ddc_data->what, reg_val, retry);
+ msleep(100);
+ goto again;
+ }
+ status = -EIO;
+ DEV_ERR("%s[%s]: failed NACK: %08x\n", __func__,
+ ddc_data->what, reg_val);
+ goto error;
+ }
+
+ DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+ return status;
+} /* hdmi_ddc_write */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index ae6f16a..47515ba 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -369,6 +369,13 @@
#define FRAME_PACKING 0x20
#define SIDE_BY_SIDE_HALF 0x40
+enum hdmi_tx_feature_type {
+ HDMI_TX_FEAT_EDID,
+ HDMI_TX_FEAT_HDCP,
+ HDMI_TX_FEAT_CEC,
+ HDMI_TX_FEAT_MAX,
+};
+
struct hdmi_disp_mode_timing_type {
u32 video_format;
u32 active_h;
@@ -389,6 +396,22 @@
u32 supported;
};
+struct hdmi_tx_ddc_ctrl {
+ void __iomem *base;
+ struct completion ddc_sw_done;
+};
+
+struct hdmi_tx_ddc_data {
+ char *what;
+ u8 *data_buf;
+ u32 data_len;
+ u32 dev_addr;
+ u32 offset;
+ u32 request_len;
+ u32 no_align;
+ int retry;
+};
+
void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix);
const char *hdmi_reg_name(u32 offset);
@@ -397,4 +420,14 @@
const char *hdmi_get_video_fmt_2string(u32 format);
ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
+/* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
+void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);
+
+/* DDC */
+void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *);
+int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *);
+int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+
#endif /* __HDMI_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 84f5909..c121772 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -14,6 +14,46 @@
#include <linux/io.h>
#include "mdss_io_util.h"
+static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
+ unsigned int type, const char *name)
+{
+ struct resource *res = NULL;
+
+ res = platform_get_resource_byname(pdev, type, name);
+ if (!res)
+ pr_err("%s: '%s' resource not found\n", __func__, name);
+
+ return res;
+}
+
+
+int msm_dss_ioremap_byname(struct platform_device *pdev,
+ struct dss_io_data *io_data, const char *name)
+{
+ struct resource *res = NULL;
+
+ if (!pdev) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
+ if (!res) {
+ pr_err("%s: '%s' msm_dss_get_res_byname failed\n",
+ __func__, name);
+ return -ENODEV;
+ }
+
+ io_data->len = resource_size(res);
+ io_data->base = ioremap(res->start, io_data->len);
+ if (!io_data->base) {
+ pr_err("%s: '%s' ioremap failed\n", __func__, name);
+ return -EIO;
+ }
+
+ return 0;
+}
+
int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
int num_vreg, int config)
{
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index 791e44a..9671414 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -14,8 +14,14 @@
#define __MDSS_IO_UTIL_H__
#include <linux/gpio.h>
+#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+struct dss_io_data {
+ u32 len;
+ void __iomem *base;
+};
+
enum dss_vreg_type {
DSS_REG_LDO,
DSS_REG_VS,
@@ -42,7 +48,10 @@
struct dss_gpio *gpio_config;
};
+int msm_dss_ioremap_byname(struct platform_device *pdev,
+ struct dss_io_data *io_data, const char *name);
int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
int num_vreg, int config);
int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable);
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index be160c4..f3b8cd1 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -531,40 +531,62 @@
static int mhl_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int ret = -ENODEV;
+ int ret;
+ struct msm_mhl_platform_data *tmp = client->dev.platform_data;
+ if (!tmp->mhl_enabled) {
+ ret = -ENODEV;
+ pr_warn("MHL feautre left disabled\n");
+ goto probe_early_exit;
+ }
mhl_msm_state->mhl_data = kzalloc(sizeof(struct msm_mhl_platform_data),
GFP_KERNEL);
if (!(mhl_msm_state->mhl_data)) {
ret = -ENOMEM;
pr_err("MHL I2C Probe failed - no mem\n");
- goto probe_exit;
+ goto probe_early_exit;
}
mhl_msm_state->i2c_client = client;
-
spin_lock_init(&mhl_state_lock);
-
i2c_set_clientdata(client, mhl_msm_state);
mhl_msm_state->mhl_data = client->dev.platform_data;
pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
mhl_msm_state->mhl_data->irq);
msc_send_workqueue = create_workqueue("mhl_msc_cmd_queue");
- if (!mhl_msm_state->mhl_data->mhl_enabled) {
- pr_info("MHL Display not enabled\n");
- return -ENODEV;
- }
-
+ mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
/* Init GPIO stuff here */
ret = mhl_sii_gpio_setup(1);
- if (ret == -1) {
+ if (ret) {
pr_err("MHL: mhl_gpio_init has failed\n");
ret = -ENODEV;
+ goto probe_early_exit;
+ }
+ mhl_sii_power_on();
+ /* MHL SII 8334 chip specific init */
+ mhl_chip_init();
+ init_completion(&mhl_msm_state->rgnd_done);
+ /* Request IRQ stuff here */
+ pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
+ mhl_msm_state->mhl_data->irq);
+ ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
+ &mhl_tx_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "mhl_tx_isr", mhl_msm_state);
+ if (ret) {
+ pr_err("request_threaded_irq failed, status: %d\n",
+ ret);
goto probe_exit;
+ } else {
+ pr_debug("request_threaded_irq succeeded\n");
}
- mhl_sii_power_on();
+ INIT_WORK(&mhl_msm_state->mhl_msc_send_work, mhl_msc_send_work);
+ INIT_LIST_HEAD(&mhl_msm_state->list_cmd);
+ mhl_msm_state->msc_command_put_work = list_cmd_put;
+ mhl_msm_state->msc_command_get_work = list_cmd_get;
+ init_completion(&mhl_msm_state->msc_cmd_done);
- pr_debug("I2C PROBE successful\n");
+ pr_debug("i2c probe successful\n");
return 0;
probe_exit:
@@ -574,6 +596,7 @@
kfree(mhl_msm_state->mhl_data);
mhl_msm_state->mhl_data = NULL;
}
+probe_early_exit:
return ret;
}
@@ -636,7 +659,6 @@
ret = -ENOMEM;
goto init_exit;
}
-
mhl_msm_state->i2c_client = NULL;
ret = i2c_add_driver(&mhl_sii_i2c_driver);
if (ret) {
@@ -645,6 +667,7 @@
goto init_exit;
} else {
if (mhl_msm_state->i2c_client == NULL) {
+ i2c_del_driver(&mhl_sii_i2c_driver);
pr_err("MHL: I2C driver add failed\n");
ret = -ENODEV;
goto init_exit;
@@ -652,36 +675,9 @@
pr_info("MHL: I2C driver added\n");
}
- /* Request IRQ stuff here */
- pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
- mhl_msm_state->mhl_data->irq);
- ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
- &mhl_tx_isr,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "mhl_tx_isr", mhl_msm_state);
- if (ret != 0) {
- pr_err("request_threaded_irq failed, status: %d\n",
- ret);
- ret = -EACCES; /* Error code???? */
- goto init_exit;
- } else
- pr_debug("request_threaded_irq succeeded\n");
-
- INIT_WORK(&mhl_msm_state->mhl_msc_send_work, mhl_msc_send_work);
- mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
- INIT_LIST_HEAD(&mhl_msm_state->list_cmd);
- mhl_msm_state->msc_command_put_work = list_cmd_put;
- mhl_msm_state->msc_command_get_work = list_cmd_get;
- init_completion(&mhl_msm_state->msc_cmd_done);
-
- /* MHL SII 8334 chip specific init */
- mhl_chip_init();
- init_completion(&mhl_msm_state->rgnd_done);
return 0;
-
init_exit:
pr_err("Exiting from the init with err\n");
- i2c_del_driver(&mhl_sii_i2c_driver);
if (!mhl_msm_state) {
kfree(mhl_msm_state);
mhl_msm_state = NULL;
@@ -846,9 +842,6 @@
if (0x02 == rgnd_imp) {
pr_debug("MHL: MHL DEVICE!!!\n");
mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
- /*
- * Handling the MHL event in driver
- */
mhl_msm_state->mhl_mode = TRUE;
if (notify_usb_online)
notify_usb_online(1);
@@ -985,8 +978,7 @@
uint8_t intr_5_stat;
/*
- * Clear INT 5 ??
- * Probably need to revisit this later
+ * Clear INT 5
* INTR5 is related to FIFO underflow/overflow reset
* which is handled in 8334 by auto FIFO reset
*/
@@ -1464,6 +1456,7 @@
}
+/* MSC, RCP, RAP messages - mandatory for compliance */
static void mhl_cbus_isr(void)
{
uint8_t regval;
@@ -1477,7 +1470,10 @@
if (regval == 0xff)
return;
- /* clear all interrupts that were raised even if we did not process */
+ /*
+ * clear all interrupts that were raised
+ * even if we did not process
+ */
if (regval)
mhl_i2c_reg_write(TX_PAGE_CBUS, 0x08, regval);
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index e6e8aca..7d534ed 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -79,6 +79,14 @@
mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND);
+ /* make sure dsi clk is on so that
+ * dcs commands can be sent
+ */
+ mipi_dsi_clk_cfg(1);
+
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+
/*
* Desctiption: change to DSI_CMD_MODE since it needed to
* tx DCS dsiplay off comamnd to panel
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 2f691cf..a7832ed 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -344,6 +344,7 @@
int mipi_dsi_cmdlist_put(struct dcs_cmd_req *cmdreq);
struct dcs_cmd_req *mipi_dsi_cmdlist_get(void);
void mipi_dsi_cmdlist_commit(int from_mdp);
+void mipi_dsi_cmd_mdp_busy(void);
#ifdef CONFIG_FB_MSM_MDP303
void update_lane_config(struct msm_panel_info *pinfo);
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 39a071b..d7992a7 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1604,10 +1604,12 @@
mipi_dsi_cmd_mdp_busy();
}
- if (req->flags && CMD_REQ_RX)
+ mipi_dsi_clk_cfg(1);
+ if (req->flags & CMD_REQ_RX)
mipi_dsi_cmdlist_rx(req);
else
mipi_dsi_cmdlist_tx(req);
+ mipi_dsi_clk_cfg(0);
mutex_unlock(&cmd_mutex);
}
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index a19d374..e76b0ae 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1167,6 +1167,8 @@
struct work_struct;
int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
+int kblockd_schedule_delayed_work(struct request_queue *q,
+ struct delayed_work *dwork, unsigned long delay);
#ifdef CONFIG_BLK_CGROUP
/*
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 8468aa5..19a1d97 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -175,17 +175,19 @@
/**
* enum qpnp_adc_channel_scaling_param - pre-scaling AMUX ratio.
- * %CHAN_PATH_SCALING1: ratio of {1, 1}
- * %CHAN_PATH_SCALING2: ratio of {1, 3}
- * %CHAN_PATH_SCALING3: ratio of {1, 4}
- * %CHAN_PATH_SCALING4: ratio of {1, 6}
+ * %CHAN_PATH_SCALING0: ratio of {1, 1}
+ * %CHAN_PATH_SCALING1: ratio of {1, 3}
+ * %CHAN_PATH_SCALING2: ratio of {1, 4}
+ * %CHAN_PATH_SCALING3: ratio of {1, 6}
+ * %CHAN_PATH_SCALING4: ratio of {1, 20}
* %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
*
* The pre-scaling is applied for signals to be within the voltage range
* of the ADC.
*/
enum qpnp_adc_channel_scaling_param {
- PATH_SCALING1 = 0,
+ PATH_SCALING0 = 0,
+ PATH_SCALING1,
PATH_SCALING2,
PATH_SCALING3,
PATH_SCALING4,
@@ -197,8 +199,8 @@
* digital data relative to ADC reference.
* %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
* %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
+ * %ADC_SCALE_PA_THERM: Returns temperature in degC.
* %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor.
* %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
* %ADC_SCALE_NONE: Do not use this scaling type.
*/
@@ -701,6 +703,75 @@
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Performs the AMUX out as 2mV/K and returns
+ * the temperature in milli degC.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in degC.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_tdkntcg_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature of the xo therm in mili
+ degC.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_vadc_is_ready() - Clients can use this API to check if the
+ * device is ready to use.
+ * @result: 0 on success and -EPROBE_DEFER when probe for the device
+ * has not occured.
+ */
+int32_t qpnp_vadc_is_ready(void);
#else
static inline int32_t qpnp_vadc_read(uint32_t channel,
struct qpnp_vadc_result *result)
@@ -712,8 +783,30 @@
{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
- const struct qpnp_adc_chan_properties *chan_prop,
- struct qpnp_adc_chan_result *chan_rslt)
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_vadc_is_read(void)
{ return -ENXIO; }
#endif
@@ -742,6 +835,13 @@
*/
int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
int32_t *result);
+/**
+ * qpnp_iadc_is_ready() - Clients can use this API to check if the
+ * device is ready to use.
+ * @result: 0 on success and -EPROBE_DEFER when probe for the device
+ * has not occured.
+ */
+int32_t qpnp_iadc_is_ready(void);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
int *result)
@@ -751,6 +851,8 @@
static inline int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
int32_t *result)
{ return -ENXIO; }
+static inline int32_t qpnp_iadc_is_read(void)
+{ return -ENXIO; }
#endif
#endif
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index a040d49..c8c2ed1 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -19,6 +19,7 @@
#define USB_AHBBURST (MSM_USB_BASE + 0x0090)
#define USB_AHBMODE (MSM_USB_BASE + 0x0098)
#define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HS_GPTIMER_BASE (MSM_USB_BASE + 0x80)
#define USB_USBCMD (MSM_USB_BASE + 0x0140)
#define USB_USBSTS (MSM_USB_BASE + 0x0144)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 295be8f..cf7b555 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -21,6 +21,11 @@
WCNSS_WLAN_SWITCH_ON,
};
+enum wcnss_hw_type {
+ WCNSS_RIVA_HW = 0,
+ WCNSS_PRONTO_HW,
+};
+
struct wcnss_wlan_config {
int use_48mhz_xo;
};
@@ -44,13 +49,17 @@
int wcnss_wlan_power(struct device *dev,
struct wcnss_wlan_config *cfg,
enum wcnss_opcode opcode);
-int req_riva_power_on_lock(char *driver_name);
-int free_riva_power_on_lock(char *driver_name);
+int wcnss_req_power_on_lock(char *driver_name);
+int wcnss_free_power_on_lock(char *driver_name);
unsigned int wcnss_get_serial_number(void);
void wcnss_flush_delayed_boot_votes(void);
void wcnss_allow_suspend(void);
void wcnss_prevent_suspend(void);
+int wcnss_hardware_type(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
+/* WLAN driver uses these names */
+#define req_riva_power_on_lock(name) wcnss_req_power_on_lock(name)
+#define free_riva_power_on_lock(name) wcnss_free_power_on_lock(name)
#endif /* _WCNSS_WLAN_H_ */
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 2a21336..4b6e6a9 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -6,3 +6,4 @@
header-y += msm_gemini.h
header-y += msm_gestures.h
header-y += msm_mercury.h
+header-y += msm_jpeg.h
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index f95230e..1d310b8 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1353,6 +1353,7 @@
uint8_t csi_lane_mask;
uint8_t csi_if;
uint8_t csid_core[2];
+ uint8_t csi_phy_sel;
};
struct msm_camera_csid_lut_params {
diff --git a/include/media/msm_jpeg.h b/include/media/msm_jpeg.h
new file mode 100644
index 0000000..11c3247
--- /dev/null
+++ b/include/media/msm_jpeg.h
@@ -0,0 +1,119 @@
+#ifndef __LINUX_MSM_JPEG_H
+#define __LINUX_MSM_JPEG_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define OUTPUT_H2V1 0
+#define OUTPUT_H2V2 1
+#define OUTPUT_BYTE 6
+
+#define MSM_JPEG_IOCTL_MAGIC 'g'
+
+#define MSM_JPEG_IOCTL_GET_HW_VERSION \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 1, struct msm_jpeg_hw_cmd *)
+
+#define MSM_JPEG_IOCTL_RESET \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd *)
+
+#define MSM_JPEG_IOCTL_STOP \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 3, struct msm_jpeg_hw_cmds *)
+
+#define MSM_JPEG_IOCTL_START \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 4, struct msm_jpeg_hw_cmds *)
+
+#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_INPUT_GET \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 7, int)
+
+#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf *)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 10, int)
+
+#define MSM_JPEG_IOCTL_EVT_GET \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd *)
+
+#define MSM_JPEG_IOCTL_EVT_GET_UNBLOCK \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 12, int)
+
+#define MSM_JPEG_IOCTL_HW_CMD \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 13, struct msm_jpeg_hw_cmd *)
+
+#define MSM_JPEG_IOCTL_HW_CMDS \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 14, struct msm_jpeg_hw_cmds *)
+
+#define MSM_JPEG_IOCTL_TEST_DUMP_REGION \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 15, unsigned long)
+
+#define MSM_JPEG_MODE_REALTIME_ENCODE 0
+#define MSM_JPEG_MODE_OFFLINE_ENCODE 1
+#define MSM_JPEG_MODE_REALTIME_ROTATION 2
+#define MSM_JPEG_MODE_OFFLINE_ROTATION 3
+
+struct msm_jpeg_ctrl_cmd {
+ uint32_t type;
+ uint32_t len;
+ void *value;
+};
+
+#define MSM_JPEG_EVT_RESET 0
+#define MSM_JPEG_EVT_SESSION_DONE 1
+#define MSM_JPEG_EVT_ERR 2
+
+struct msm_jpeg_buf {
+ uint32_t type;
+ int fd;
+
+ void *vaddr;
+
+ uint32_t y_off;
+ uint32_t y_len;
+ uint32_t framedone_len;
+
+ uint32_t cbcr_off;
+ uint32_t cbcr_len;
+
+ uint32_t num_of_mcu_rows;
+ uint32_t offset;
+};
+
+#define MSM_JPEG_HW_CMD_TYPE_READ 0
+#define MSM_JPEG_HW_CMD_TYPE_WRITE 1
+#define MSM_JPEG_HW_CMD_TYPE_WRITE_OR 2
+#define MSM_JPEG_HW_CMD_TYPE_UWAIT 3
+#define MSM_JPEG_HW_CMD_TYPE_MWAIT 4
+#define MSM_JPEG_HW_CMD_TYPE_MDELAY 5
+#define MSM_JPEG_HW_CMD_TYPE_UDELAY 6
+struct msm_jpeg_hw_cmd {
+
+ uint32_t type:4;
+
+ /* n microseconds of timeout for WAIT */
+ /* n microseconds of time for DELAY */
+ /* repeat n times for READ/WRITE */
+ /* max is 0xFFF, 4095 */
+ uint32_t n:12;
+ uint32_t offset:16;
+ uint32_t mask;
+ union {
+ uint32_t data; /* for single READ/WRITE/WAIT, n = 1 */
+ uint32_t *pdata; /* for multiple READ/WRITE/WAIT, n > 1 */
+ };
+};
+
+struct msm_jpeg_hw_cmds {
+ uint32_t m; /* number of elements in the hw_cmd array */
+ struct msm_jpeg_hw_cmd hw_cmd[1];
+};
+
+#endif /* __LINUX_MSM_JPEG_H */
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index b80a0a9..05786a7 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -42,10 +43,8 @@
#define SAMPLE_RATE_8KHZ 8000
#define SAMPLE_RATE_16KHZ 16000
-#define BOTTOM_SPK_AMP_POS 0x1
-#define BOTTOM_SPK_AMP_NEG 0x2
-#define TOP_SPK_AMP_POS 0x4
-#define TOP_SPK_AMP_NEG 0x8
+#define TOP_AND_BOTTOM_SPK_AMP_POS 0x1
+#define TOP_AND_BOTTOM_SPK_AMP_NEG 0x2
#define GPIO_AUX_PCM_DOUT 23
#define GPIO_AUX_PCM_DIN 22
@@ -62,6 +61,10 @@
#define TABLA_MBHC_DEF_BUTTONS 8
#define TABLA_MBHC_DEF_RLOADS 5
+#define PM8018_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+#define JACK_DETECT_GPIO 3
+#define JACK_DETECT_INT PM8018_GPIO_IRQ(PM8018_IRQ_BASE, JACK_DETECT_GPIO)
+
/*
* Added for I2S
*/
@@ -245,16 +248,13 @@
/*
* Added for I2S
*/
-
-static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(3);
-static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
+static u32 top_and_bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
void *sif_virt_addr;
void *secpcm_portslc_virt_addr;
static int mdm9615_spk_control;
-static int mdm9615_ext_bottom_spk_pamp;
-static int mdm9615_ext_top_spk_pamp;
+static int mdm9615_ext_top_and_bottom_spk_pamp;
static int mdm9615_slim_0_rx_ch = 1;
static int mdm9615_slim_0_tx_ch = 1;
@@ -271,6 +271,14 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static bool hs_detect_use_gpio;
+module_param(hs_detect_use_gpio, bool, 0444);
+MODULE_PARM_DESC(hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool hs_detect_use_firmware;
+module_param(hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(hs_detect_use_firmware, "Use firmware for headset detection");
+
static int mdm9615_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
static struct tabla_mbhc_config mbhc_cfg = {
@@ -300,39 +308,26 @@
.function = PM_GPIO_FUNC_NORMAL,
};
- if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+ if (spk_amp_gpio == top_and_bottom_spk_pamp_gpio) {
- ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+ ret = gpio_request(top_and_bottom_spk_pamp_gpio,
+ "TOP_AND_BOTTOM_SPK_AMP");
if (ret) {
- pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
- __func__, bottom_spk_pamp_gpio);
+ pr_err("%s: Error requesting TOP AND BOTTOM SPK AMP GPIO %u\n",
+ __func__, top_and_bottom_spk_pamp_gpio);
return;
}
- ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, ¶m);
+ ret = pm8xxx_gpio_config(top_and_bottom_spk_pamp_gpio, ¶m);
if (ret)
- pr_err("%s: Failed to configure Bottom Spk Ampl"
- " gpio %u\n", __func__, bottom_spk_pamp_gpio);
+ pr_err("%s: Failed to configure Top & Bottom Spk Ampl\n"
+ "gpio %u\n", __func__,
+ top_and_bottom_spk_pamp_gpio);
else {
- pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
- gpio_direction_output(bottom_spk_pamp_gpio, 1);
+ pr_debug("%s: enable Top & Bottom spkr amp gpio\n",
+ __func__);
+ gpio_direction_output(top_and_bottom_spk_pamp_gpio, 1);
}
- } else if (spk_amp_gpio == top_spk_pamp_gpio) {
-
- ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
- if (ret) {
- pr_err("%s: Error requesting GPIO %d\n", __func__,
- top_spk_pamp_gpio);
- return;
- }
- ret = pm8xxx_gpio_config(top_spk_pamp_gpio, ¶m);
- if (ret)
- pr_err("%s: Failed to configure Top Spk Ampl"
- " gpio %u\n", __func__, top_spk_pamp_gpio);
- else {
- pr_debug("%s: enable Top spkr amp gpio\n", __func__);
- gpio_direction_output(top_spk_pamp_gpio, 1);
- }
} else {
pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
" gpio = %u\n", __func__, spk_amp_gpio);
@@ -342,49 +337,30 @@
static void mdm9615_ext_spk_power_amp_on(u32 spk)
{
- if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
-
- if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
- (mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
-
- pr_debug("%s() External Bottom Speaker Ampl already "
+ if (spk & (TOP_AND_BOTTOM_SPK_AMP_POS | TOP_AND_BOTTOM_SPK_AMP_NEG)) {
+ if ((mdm9615_ext_top_and_bottom_spk_pamp &
+ TOP_AND_BOTTOM_SPK_AMP_POS) &&
+ (mdm9615_ext_top_and_bottom_spk_pamp &
+ TOP_AND_BOTTOM_SPK_AMP_NEG)) {
+ pr_debug("%s() External Speaker Ampl already "
"turned on. spk = 0x%08x\n", __func__, spk);
return;
}
- mdm9615_ext_bottom_spk_pamp |= spk;
+ mdm9615_ext_top_and_bottom_spk_pamp |= spk;
- if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
- (mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
-
- mdm9615_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
- pr_debug("%s: slepping 4 ms after turning on external "
- " Bottom Speaker Ampl\n", __func__);
+ if ((mdm9615_ext_top_and_bottom_spk_pamp &
+ TOP_AND_BOTTOM_SPK_AMP_POS) &&
+ (mdm9615_ext_top_and_bottom_spk_pamp &
+ TOP_AND_BOTTOM_SPK_AMP_NEG)) {
+ mdm9615_enable_ext_spk_amp_gpio(
+ top_and_bottom_spk_pamp_gpio);
+ pr_debug("%s: slepping 4 ms after turning on external\n"
+ "Speaker Ampl\n", __func__);
usleep_range(4000, 4000);
}
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
- if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
- pr_debug("%s() External Top Speaker Ampl already"
- "turned on. spk = 0x%08x\n", __func__, spk);
- return;
- }
-
- mdm9615_ext_top_spk_pamp |= spk;
-
- if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
- mdm9615_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
- pr_debug("%s: sleeping 4 ms after turning on "
- " external Top Speaker Ampl\n", __func__);
- usleep_range(4000, 4000);
- }
- } else {
-
+ } else {
pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
__func__, spk);
return;
@@ -393,33 +369,20 @@
static void mdm9615_ext_spk_power_amp_off(u32 spk)
{
- if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+ if (spk & (TOP_AND_BOTTOM_SPK_AMP_POS | TOP_AND_BOTTOM_SPK_AMP_NEG)) {
- if (!mdm9615_ext_bottom_spk_pamp)
+ if (!mdm9615_ext_top_and_bottom_spk_pamp)
return;
- gpio_direction_output(bottom_spk_pamp_gpio, 0);
- gpio_free(bottom_spk_pamp_gpio);
- mdm9615_ext_bottom_spk_pamp = 0;
+ gpio_direction_output(top_and_bottom_spk_pamp_gpio, 0);
+ gpio_free(top_and_bottom_spk_pamp_gpio);
+ mdm9615_ext_top_and_bottom_spk_pamp = 0;
pr_debug("%s: sleeping 4 ms after turning off external Bottom"
" Speaker Ampl\n", __func__);
usleep_range(4000, 4000);
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
- if (!mdm9615_ext_top_spk_pamp)
- return;
-
- gpio_direction_output(top_spk_pamp_gpio, 0);
- gpio_free(top_spk_pamp_gpio);
- mdm9615_ext_top_spk_pamp = 0;
-
- pr_debug("%s: sleeping 4 ms after turning off external Top"
- " Spkaker Ampl\n", __func__);
-
- usleep_range(4000, 4000);
} else {
pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
@@ -434,15 +397,11 @@
pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
if (mdm9615_spk_control == MDM9615_SPK_ON) {
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Neg");
} else {
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Pos");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Neg");
}
snd_soc_dapm_sync(dapm);
@@ -474,14 +433,12 @@
pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
if (SND_SOC_DAPM_EVENT_ON(event)) {
- if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
- mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
- mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
- else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
- mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
- mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+ if (!strncmp(w->name, "Ext Spk Pos", 11))
+ mdm9615_ext_spk_power_amp_on(
+ TOP_AND_BOTTOM_SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Neg", 11))
+ mdm9615_ext_spk_power_amp_on(
+ TOP_AND_BOTTOM_SPK_AMP_NEG);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
@@ -489,14 +446,12 @@
}
} else {
- if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
- mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
- mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
- else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
- mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
- mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+ if (!strncmp(w->name, "Ext Spk Pos", 11))
+ mdm9615_ext_spk_power_amp_off(
+ TOP_AND_BOTTOM_SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Neg", 11))
+ mdm9615_ext_spk_power_amp_off(
+ TOP_AND_BOTTOM_SPK_AMP_NEG);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
@@ -557,11 +512,8 @@
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
mdm9615_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", mdm9615_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", mdm9615_spkramp_event),
-
- SND_SOC_DAPM_SPK("Ext Spk Top Pos", mdm9615_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Top Neg", mdm9615_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Pos", mdm9615_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Neg", mdm9615_spkramp_event),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -584,11 +536,11 @@
{"LDO_H", NULL, "MCLK"},
/* Speaker path */
- {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
- {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+ {"Ext Spk Pos", NULL, "LINEOUT1"},
+ {"Ext Spk Neg", NULL, "LINEOUT3"},
- {"Ext Spk Top Pos", NULL, "LINEOUT2"},
- {"Ext Spk Top Neg", NULL, "LINEOUT4"},
+ {"Ext Spk Pos", NULL, "LINEOUT2"},
+ {"Ext Spk Neg", NULL, "LINEOUT4"},
/* Microphone path */
{"AMIC1", NULL, "MIC BIAS1 External"},
@@ -1006,10 +958,8 @@
snd_soc_dapm_add_routes(dapm, common_audio_map,
ARRAY_SIZE(common_audio_map));
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Neg");
snd_soc_dapm_sync(dapm);
@@ -1510,6 +1460,13 @@
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct pm_gpio jack_gpio_cfg = {
+ .direction = PM_GPIO_DIR_IN,
+ .pull = PM_GPIO_PULL_NO,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .vin_sel = 2,
+ .inv_int_pol = 0,
+ };
pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
@@ -1521,10 +1478,8 @@
snd_soc_dapm_add_routes(dapm, common_audio_map,
ARRAY_SIZE(common_audio_map));
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Neg");
snd_soc_dapm_sync(dapm);
@@ -1545,6 +1500,22 @@
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ if (hs_detect_use_gpio) {
+ mbhc_cfg.gpio = PM8018_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
+ mbhc_cfg.gpio_irq = JACK_DETECT_INT;
+ }
+
+ if (mbhc_cfg.gpio) {
+ err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
+ if (err) {
+ pr_err("%s: pm8xxx_gpio_config JACK_DETECT failed %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+
+ mbhc_cfg.read_fw_bin = hs_detect_use_firmware;
+
err = tabla_hs_detect(codec, &mbhc_cfg);
return err;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 011912e..16a4aaa 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -199,7 +199,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -225,7 +225,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -240,7 +240,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -255,7 +255,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index a33a01f..5b0759c 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -47,11 +47,11 @@
static struct snd_msm_volume multi_ch_pcm_audio = {NULL, 0x2000};
#define PLAYBACK_NUM_PERIODS 8
-#define PLAYBACK_MAX_PERIOD_SIZE 4032
+#define PLAYBACK_MAX_PERIOD_SIZE 12288
#define PLAYBACK_MIN_PERIOD_SIZE 256
#define CAPTURE_NUM_PERIODS 16
#define CAPTURE_MIN_PERIOD_SIZE 320
-#define CAPTURE_MAX_PERIOD_SIZE 5376
+#define CAPTURE_MAX_PERIOD_SIZE 12288
static struct snd_pcm_hardware msm_pcm_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -303,8 +303,8 @@
pr_debug("Samp_rate = %d\n", prtd->samp_rate);
pr_debug("Channel = %d\n", prtd->channel_mode);
- ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
- prtd->channel_mode);
+ ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+ prtd->samp_rate, prtd->channel_mode);
if (ret < 0)
pr_debug("%s: cmd cfg pcm was block failed", __func__);
@@ -399,7 +399,8 @@
/* Capture path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
runtime->hw = msm_pcm_hardware_capture;
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+ ret = q6asm_open_read(prtd->audio_client,
+ FORMAT_MULTI_CHANNEL_LINEAR_PCM);
if (ret < 0) {
pr_err("%s: pcm in open failed\n", __func__);
q6asm_audio_client_free(prtd->audio_client);
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 633973e..c5e2f09 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -464,6 +464,7 @@
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(SGLTE_SESSION_NAME), tty_mode);
return 0;
}
static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
@@ -475,7 +476,8 @@
voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
wv_enable);
-
+ voc_set_widevoice_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+ wv_enable);
return 0;
}
@@ -497,6 +499,8 @@
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
MODULE_ID_VOICE_MODULE_ST, st_enable);
+ voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
return 0;
}
@@ -519,6 +523,8 @@
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
return 0;
}
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 1aac158..3a226b4 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1885,7 +1885,16 @@
enc_cfg.enc_blk.cfg.mpcm.sample_rate = rate;
enc_cfg.enc_blk.cfg.mpcm.is_signed = 1;
enc_cfg.enc_blk.cfg.mpcm.is_interleaved = 1;
- if (channels == 2) {
+ if (channels == 1) {
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+ } else if (channels == 2) {
enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = 0;
@@ -2040,6 +2049,11 @@
} else if (num_channels == 2) {
channel_mapping[0] = PCM_CHANNEL_FL;
channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (num_channels == 4) {
+ channel_mapping[0] = PCM_CHANNEL_FL;
+ channel_mapping[1] = PCM_CHANNEL_FR;
+ channel_mapping[1] = PCM_CHANNEL_LB;
+ channel_mapping[1] = PCM_CHANNEL_RB;
} else if (num_channels == 6) {
channel_mapping[0] = PCM_CHANNEL_FC;
channel_mapping[1] = PCM_CHANNEL_FL;
@@ -2047,6 +2061,15 @@
channel_mapping[3] = PCM_CHANNEL_LB;
channel_mapping[4] = PCM_CHANNEL_RB;
channel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (num_channels == 8) {
+ channel_mapping[0] = PCM_CHANNEL_FC;
+ channel_mapping[1] = PCM_CHANNEL_FL;
+ channel_mapping[2] = PCM_CHANNEL_FR;
+ channel_mapping[3] = PCM_CHANNEL_LB;
+ channel_mapping[4] = PCM_CHANNEL_RB;
+ channel_mapping[5] = PCM_CHANNEL_LFE;
+ channel_mapping[6] = PCM_CHANNEL_FLC;
+ channel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
num_channels);
@@ -2303,6 +2326,11 @@
} else if (channels == 2) {
channel_mapping[0] = PCM_CHANNEL_FL;
channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ channel_mapping[0] = PCM_CHANNEL_FL;
+ channel_mapping[1] = PCM_CHANNEL_FR;
+ channel_mapping[1] = PCM_CHANNEL_LB;
+ channel_mapping[1] = PCM_CHANNEL_RB;
} else if (channels == 6) {
channel_mapping[0] = PCM_CHANNEL_FC;
channel_mapping[1] = PCM_CHANNEL_FL;
@@ -2310,6 +2338,15 @@
channel_mapping[3] = PCM_CHANNEL_LB;
channel_mapping[4] = PCM_CHANNEL_RB;
channel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (channels == 8) {
+ channel_mapping[0] = PCM_CHANNEL_FC;
+ channel_mapping[1] = PCM_CHANNEL_FL;
+ channel_mapping[2] = PCM_CHANNEL_FR;
+ channel_mapping[3] = PCM_CHANNEL_LB;
+ channel_mapping[4] = PCM_CHANNEL_RB;
+ channel_mapping[5] = PCM_CHANNEL_LFE;
+ channel_mapping[6] = PCM_CHANNEL_FLC;
+ channel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
channels);
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 360744a..6f3249a 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -279,7 +279,6 @@
static int msm_compr_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct compr_audio *compr;
struct msm_audio *prtd;
int ret = 0;
@@ -319,9 +318,6 @@
pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
-
prtd->cmd_ack = 1;
ret = snd_pcm_hw_constraint_list(runtime, 0,
@@ -460,6 +456,7 @@
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct compr_audio *compr = runtime->private_data;
struct msm_audio *prtd = &compr->prtd;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
@@ -477,6 +474,9 @@
pr_err("%s: Session out open failed\n", __func__);
return -ENOMEM;
}
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+
ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
if (ret < 0) {
pr_err("%s: Set IO mode failed\n", __func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 047e0f0..54f379f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -57,11 +57,11 @@
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
- .buffer_bytes_max = 2 * 1024 * 1024,
+ .buffer_bytes_max = 1024 * 1024,
.period_bytes_min = 128 * 1024,
- .period_bytes_max = 512 * 1024,
+ .period_bytes_max = 256 * 1024,
.periods_min = 4,
- .periods_max = 16,
+ .periods_max = 8,
.fifo_size = 0,
};
@@ -87,7 +87,6 @@
unsigned long flag = 0;
int i = 0;
- pr_debug("%s\n", __func__);
spin_lock_irqsave(&the_locks.event_lock, flag);
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2: {
@@ -110,12 +109,16 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
- break;
+
+ buf = prtd->audio_client->port[IN].buf;
+ if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+ memset((void *)buf[0].data +
+ (prtd->out_head * prtd->pcm_count),
+ 0, prtd->pcm_count);
+ }
pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
__func__, prtd->pcm_count);
- buf = prtd->audio_client->port[IN].buf;
param.paddr = (unsigned long)buf[0].phys
+ (prtd->out_head * prtd->pcm_count);
param.len = prtd->pcm_count;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index c9f9593..7483bb6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -107,7 +107,6 @@
uint32_t idx = 0;
uint32_t size = 0;
- pr_err("%s\n", __func__);
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2: {
pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n");
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 392b9b0..714b2ce 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1060,8 +1060,8 @@
pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
__func__,
payload[0], payload[1], payload[2]);
- ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
- payload[2]);
+ ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
+ payload[1]);
if (atomic_read(&ac->cmd_state)) {
atomic_set(&ac->cmd_state, 0);
wake_up(&ac->cmd_wait);